| line | stmt | bran | cond | sub | pod | time | code | 
| 1 |  |  |  |  |  |  | #define IMAGER_NO_CONTEXT | 
| 2 |  |  |  |  |  |  | #include "imager.h" | 
| 3 |  |  |  |  |  |  | #include "imageri.h" | 
| 4 |  |  |  |  |  |  |  | 
| 5 |  |  |  |  |  |  | IMAGER_STATIC_INLINE int | 
| 6 | 3168 |  |  |  |  |  | match_one_color(const i_sample_t *testme, const i_trim_colors_t *test) { | 
| 7 | 3168 | 100 |  |  |  |  | if (test->c1.channel[0] > testme[0] || test->c2.channel[0] < testme[0]) | 
|  |  | 100 |  |  |  |  |  | 
| 8 | 670 |  |  |  |  |  | return 0; | 
| 9 | 2498 | 100 |  |  |  |  | if (test->c1.channel[1] > testme[1] || test->c2.channel[1] < testme[1]) | 
|  |  | 100 |  |  |  |  |  | 
| 10 | 204 |  |  |  |  |  | return 0; | 
| 11 | 2294 | 50 |  |  |  |  | if (test->c1.channel[2] > testme[2] || test->c2.channel[2] < testme[2]) | 
|  |  | 100 |  |  |  |  |  | 
| 12 | 8 |  |  |  |  |  | return 0; | 
| 13 | 2286 |  |  |  |  |  | return 1; | 
| 14 |  |  |  |  |  |  | } | 
| 15 |  |  |  |  |  |  |  | 
| 16 |  |  |  |  |  |  | IMAGER_STATIC_INLINE int | 
| 17 | 0 |  |  |  |  |  | match_one_fcolor(const i_fsample_t *testme, const i_trim_colors_t *test) { | 
| 18 | 0 | 0 |  |  |  |  | if (test->cf1.channel[0] > testme[0] || test->cf2.channel[0] < testme[0]) | 
|  |  | 0 |  |  |  |  |  | 
| 19 | 0 |  |  |  |  |  | return 0; | 
| 20 | 0 | 0 |  |  |  |  | if (test->cf1.channel[1] > testme[1] || test->cf2.channel[1] < testme[1]) | 
|  |  | 0 |  |  |  |  |  | 
| 21 | 0 |  |  |  |  |  | return 0; | 
| 22 | 0 | 0 |  |  |  |  | if (test->cf1.channel[2] > testme[2] || test->cf2.channel[2] < testme[2]) | 
|  |  | 0 |  |  |  |  |  | 
| 23 | 0 |  |  |  |  |  | return 0; | 
| 24 | 0 |  |  |  |  |  | return 1; | 
| 25 |  |  |  |  |  |  | } | 
| 26 |  |  |  |  |  |  |  | 
| 27 |  |  |  |  |  |  | IMAGER_STATIC_INLINE int | 
| 28 | 2340 |  |  |  |  |  | match_any_color(const i_sample_t *testme, const i_trim_colors_t *tests, int count) { | 
| 29 |  |  |  |  |  |  | int i; | 
| 30 | 3222 | 100 |  |  |  |  | for (i = 0; i < count; ++i) { | 
| 31 | 3168 | 100 |  |  |  |  | if (match_one_color(testme, tests+i)) | 
| 32 | 2286 |  |  |  |  |  | return 1; | 
| 33 |  |  |  |  |  |  | } | 
| 34 | 54 |  |  |  |  |  | return 0; | 
| 35 |  |  |  |  |  |  | } | 
| 36 |  |  |  |  |  |  |  | 
| 37 |  |  |  |  |  |  | IMAGER_STATIC_INLINE int | 
| 38 | 0 |  |  |  |  |  | match_any_fcolor(const i_fsample_t *testme, const i_trim_colors_t *tests, int count) { | 
| 39 |  |  |  |  |  |  | int i; | 
| 40 | 0 | 0 |  |  |  |  | for (i = 0; i < count; ++i) { | 
| 41 | 0 | 0 |  |  |  |  | if (match_one_fcolor(testme, tests+i)) | 
| 42 | 0 |  |  |  |  |  | return 1; | 
| 43 |  |  |  |  |  |  | } | 
| 44 | 0 |  |  |  |  |  | return 0; | 
| 45 |  |  |  |  |  |  | } | 
| 46 |  |  |  |  |  |  |  | 
| 47 |  |  |  |  |  |  | #!define MATCH_ANY_COLOR match_any_color match_any_fcolor | 
| 48 |  |  |  |  |  |  |  | 
| 49 |  |  |  |  |  |  | static const int gray_chans[4] = { 0, 0, 0, 1 }; | 
| 50 |  |  |  |  |  |  |  | 
| 51 |  |  |  |  |  |  | #define TEST_COLOR(s) 					    \ | 
| 52 |  |  |  |  |  |  | (color_count && MATCH_ANY_COLOR((s), colors, color_count) ||	\ | 
| 53 |  |  |  |  |  |  | check_alpha && (s)[3] <= work_threshold) | 
| 54 |  |  |  |  |  |  |  | 
| 55 | 12 |  |  |  |  |  | static int | 
| 56 |  |  |  |  |  |  | trim_rect_simple(i_img *im, double transp_threshold, int color_count, | 
| 57 |  |  |  |  |  |  | const i_trim_colors_t *colors, i_img_dim *left, i_img_dim *top, | 
| 58 | 12 |  |  |  |  |  | i_img_dim *right, i_img_dim *bottom) { | 
| 59 | 12 | 50 |  |  |  |  | const int color_chans = i_img_color_channels(im); | 
| 60 | 12 |  |  |  |  |  | const int *chans = color_chans == 1 ? gray_chans : NULL; | 
| 61 | 12 | 100 |  |  |  |  | const int has_alpha = i_img_has_alpha(im); | 
|  |  | 50 |  |  |  |  |  | 
| 62 | 12 | 100 |  |  |  |  | const int check_alpha = has_alpha && transp_threshold < 1.0; | 
| 63 |  |  |  |  |  |  | const int chan_count = check_alpha ? 4 : 3; | 
| 64 |  |  |  |  |  |  | i_img_dim x, y; | 
| 65 | 12 | 50 |  |  |  |  | #code im->bits <= 8 | 
| 66 | 12 |  |  |  |  |  | IM_SAMPLE_T *samps = mymalloc(sizeof(IM_SAMPLE_T) * im->ysize * chan_count); | 
| 67 |  |  |  |  |  |  | #if IM_EIGHT_BIT | 
| 68 | 12 |  |  |  |  |  | const IM_WORK_T work_threshold = floor(IM_SAMPLE_MAX * transp_threshold); | 
| 69 |  |  |  |  |  |  | #else | 
| 70 | 0 |  |  |  |  |  | const IM_WORK_T work_threshold = transp_threshold; | 
| 71 |  |  |  |  |  |  | #endif | 
| 72 |  |  |  |  |  |  |  | 
| 73 |  |  |  |  |  |  | /* scan down from top */ | 
| 74 | 32 | 50 |  |  |  |  | for (y = 0; y < im->ysize; ++y) { | 
|  |  | 0 |  |  |  |  |  | 
| 75 |  |  |  |  |  |  | IM_SAMPLE_T *s; | 
| 76 | 32 |  |  |  |  |  | IM_GSAMP(im, 0, im->xsize, y, samps, chans, chan_count); | 
| 77 | 472 | 100 |  |  |  |  | for (x = 0, s = samps; x < im->xsize; ++x, s += chan_count) { | 
|  |  | 0 |  |  |  |  |  | 
| 78 | 452 | 100 |  |  |  |  | if (!TEST_COLOR(s)) | 
|  |  | 100 |  |  |  |  |  | 
|  |  | 100 |  |  |  |  |  | 
|  |  | 100 |  |  |  |  |  | 
|  |  | 0 |  |  |  |  |  | 
|  |  | 0 |  |  |  |  |  | 
|  |  | 0 |  |  |  |  |  | 
|  |  | 0 |  |  |  |  |  | 
| 79 |  |  |  |  |  |  | break; | 
| 80 |  |  |  |  |  |  | } | 
| 81 | 32 | 100 |  |  |  |  | if (x < im->xsize) | 
|  |  | 0 |  |  |  |  |  | 
| 82 | 12 |  |  |  |  |  | break; | 
| 83 |  |  |  |  |  |  | } | 
| 84 | 12 |  |  |  |  |  | *top = y; | 
| 85 | 12 | 50 |  |  |  |  | if (y < im->ysize) { | 
|  |  | 0 |  |  |  |  |  | 
| 86 |  |  |  |  |  |  | /* scan from the bottom */ | 
| 87 | 52 | 50 |  |  |  |  | for (y = im->ysize-1; y >= 0; --y) { | 
|  |  | 0 |  |  |  |  |  | 
| 88 |  |  |  |  |  |  | IM_SAMPLE_T *s; | 
| 89 | 52 |  |  |  |  |  | IM_GSAMP(im, 0, im->xsize, y, samps, chans, chan_count); | 
| 90 | 892 | 100 |  |  |  |  | for (x = 0, s = samps; x < im->xsize; ++x, s += chan_count) { | 
|  |  | 0 |  |  |  |  |  | 
| 91 | 852 | 100 |  |  |  |  | if (!TEST_COLOR(s)) | 
|  |  | 100 |  |  |  |  |  | 
|  |  | 100 |  |  |  |  |  | 
|  |  | 100 |  |  |  |  |  | 
|  |  | 0 |  |  |  |  |  | 
|  |  | 0 |  |  |  |  |  | 
|  |  | 0 |  |  |  |  |  | 
|  |  | 0 |  |  |  |  |  | 
| 92 |  |  |  |  |  |  | break; | 
| 93 |  |  |  |  |  |  | } | 
| 94 | 52 | 100 |  |  |  |  | if (x < im->xsize) | 
|  |  | 0 |  |  |  |  |  | 
| 95 | 12 |  |  |  |  |  | break; | 
| 96 |  |  |  |  |  |  | } | 
| 97 | 12 |  |  |  |  |  | *bottom = im->ysize - y - 1; | 
| 98 |  |  |  |  |  |  |  | 
| 99 |  |  |  |  |  |  | /* we've trimmed top and bottom, now the sides */ | 
| 100 | 12 |  |  |  |  |  | *left = *right = im->xsize; | 
| 101 | 192 | 100 |  |  |  |  | for (y = *top; y < im->ysize - *bottom && (*left || *right); ++y) { | 
|  |  | 50 |  |  |  |  |  | 
|  |  | 0 |  |  |  |  |  | 
|  |  | 0 |  |  |  |  |  | 
|  |  | 0 |  |  |  |  |  | 
|  |  | 0 |  |  |  |  |  | 
| 102 |  |  |  |  |  |  | IM_SAMPLE_T *s; | 
| 103 | 180 |  |  |  |  |  | IM_GSAMP(im, 0, im->xsize, y, samps, chans, chan_count); | 
| 104 | 676 | 100 |  |  |  |  | for (x = 0, s = samps; x < *left; ++x, s += chan_count) { | 
|  |  | 0 |  |  |  |  |  | 
| 105 | 512 | 100 |  |  |  |  | if (!TEST_COLOR(s)) { | 
|  |  | 100 |  |  |  |  |  | 
|  |  | 100 |  |  |  |  |  | 
|  |  | 100 |  |  |  |  |  | 
|  |  | 0 |  |  |  |  |  | 
|  |  | 0 |  |  |  |  |  | 
|  |  | 0 |  |  |  |  |  | 
|  |  | 0 |  |  |  |  |  | 
| 106 | 16 |  |  |  |  |  | *left = x; | 
| 107 | 16 |  |  |  |  |  | break; | 
| 108 |  |  |  |  |  |  | } | 
| 109 |  |  |  |  |  |  | } | 
| 110 | 868 | 100 |  |  |  |  | for (x = im->xsize - 1, s = samps + chan_count * im->xsize; | 
|  |  | 0 |  |  |  |  |  | 
| 111 | 688 |  |  |  |  |  | x >= im->xsize - *right; --x, s -= chan_count) { | 
| 112 | 706 | 100 |  |  |  |  | if (!TEST_COLOR(s-chan_count)) { | 
|  |  | 100 |  |  |  |  |  | 
|  |  | 100 |  |  |  |  |  | 
|  |  | 100 |  |  |  |  |  | 
|  |  | 0 |  |  |  |  |  | 
|  |  | 0 |  |  |  |  |  | 
|  |  | 0 |  |  |  |  |  | 
|  |  | 0 |  |  |  |  |  | 
| 113 | 18 |  |  |  |  |  | *right = im->xsize - x - 1; | 
| 114 | 18 |  |  |  |  |  | break; | 
| 115 |  |  |  |  |  |  | } | 
| 116 |  |  |  |  |  |  | } | 
| 117 |  |  |  |  |  |  | } | 
| 118 |  |  |  |  |  |  | } | 
| 119 |  |  |  |  |  |  | else { | 
| 120 |  |  |  |  |  |  | /* whole image can be trimmed */ | 
| 121 | 0 |  |  |  |  |  | *left = im->xsize; | 
| 122 | 0 |  |  |  |  |  | *right = *bottom = 0; | 
| 123 |  |  |  |  |  |  | } | 
| 124 | 12 |  |  |  |  |  | myfree(samps); | 
| 125 |  |  |  |  |  |  | #/code | 
| 126 |  |  |  |  |  |  |  | 
| 127 | 12 |  |  |  |  |  | return 1; | 
| 128 |  |  |  |  |  |  | } | 
| 129 |  |  |  |  |  |  |  | 
| 130 |  |  |  |  |  |  | int | 
| 131 | 12 |  |  |  |  |  | i_trim_rect(i_img *im, double transp_threshold, int color_count, const i_trim_colors_t *colors, | 
| 132 |  |  |  |  |  |  | i_img_dim *left, i_img_dim *top, i_img_dim *right, i_img_dim *bottom) { | 
| 133 | 12 |  |  |  |  |  | dIMCTXim(im); | 
| 134 | 12 |  |  |  |  |  | i_trim_colors_t *tcolors = NULL; | 
| 135 |  |  |  |  |  |  | i_trim_colors_t *tcolorp; | 
| 136 |  |  |  |  |  |  | const i_trim_colors_t *colorp; | 
| 137 | 12 |  |  |  |  |  | int tcolor_count = 0; | 
| 138 |  |  |  |  |  |  | int result; | 
| 139 |  |  |  |  |  |  |  | 
| 140 | 12 | 100 |  |  |  |  | if (color_count) { | 
| 141 | 11 |  |  |  |  |  | tcolors = mymalloc(sizeof(i_trim_colors_t) * color_count); | 
| 142 | 11 |  |  |  |  |  | tcolorp = tcolors; | 
| 143 |  |  |  |  |  |  | /* convert 8-bit to float colors, or float colors to 8-bit depending on the | 
| 144 |  |  |  |  |  |  | image type. | 
| 145 |  |  |  |  |  |  | */ | 
| 146 | 11 | 50 |  |  |  |  | if (im->bits <= 8) { | 
| 147 |  |  |  |  |  |  | int i, ch; | 
| 148 | 41 | 100 |  |  |  |  | for (i = 0, colorp = colors; i < color_count; ++i, ++colorp) { | 
| 149 | 30 | 50 |  |  |  |  | if (colorp->is_float) { | 
| 150 | 0 | 0 |  |  |  |  | for (ch = 0; ch < 3; ++ch) { | 
| 151 | 0 |  |  |  |  |  | tcolorp->c1.channel[ch] = ceil(colorp->cf1.channel[ch] * 255); | 
| 152 | 0 |  |  |  |  |  | tcolorp->c2.channel[ch] = floor(colorp->cf2.channel[ch] * 255); | 
| 153 |  |  |  |  |  |  | } | 
| 154 |  |  |  |  |  |  | } | 
| 155 |  |  |  |  |  |  | else { | 
| 156 | 30 |  |  |  |  |  | *tcolorp = *colorp; | 
| 157 |  |  |  |  |  |  | } | 
| 158 | 120 | 100 |  |  |  |  | for (ch = 0; ch < 3; ++ch) { | 
| 159 | 90 | 50 |  |  |  |  | if (tcolorp->c1.channel[ch] > tcolorp->c2.channel[ch]) | 
| 160 | 0 |  |  |  |  |  | break; | 
| 161 |  |  |  |  |  |  | } | 
| 162 | 30 | 50 |  |  |  |  | if (ch == 3) { | 
| 163 | 30 |  |  |  |  |  | ++tcolorp, ++tcolor_count; | 
| 164 |  |  |  |  |  |  | } | 
| 165 |  |  |  |  |  |  | } | 
| 166 |  |  |  |  |  |  | /* TODO optimize where the image is greyscale to remove color ranges that don't | 
| 167 |  |  |  |  |  |  | overlap the greyscale line | 
| 168 |  |  |  |  |  |  | */ | 
| 169 |  |  |  |  |  |  | } | 
| 170 |  |  |  |  |  |  | else { | 
| 171 |  |  |  |  |  |  | int i, ch; | 
| 172 | 0 | 0 |  |  |  |  | for (i = 0, colorp = colors; i < color_count; ++i, ++colorp) { | 
| 173 | 0 | 0 |  |  |  |  | if (!colorp->is_float) { | 
| 174 | 0 | 0 |  |  |  |  | for (ch = 0; ch < 3; ++ch) { | 
| 175 | 0 |  |  |  |  |  | tcolorp->cf1.channel[ch] = colorp->c1.channel[ch] / 255.0; | 
| 176 | 0 |  |  |  |  |  | tcolorp->cf2.channel[ch] = colorp->c2.channel[ch] / 255.0; | 
| 177 |  |  |  |  |  |  | } | 
| 178 |  |  |  |  |  |  | } | 
| 179 |  |  |  |  |  |  | else { | 
| 180 | 0 |  |  |  |  |  | *tcolorp = *colors; | 
| 181 |  |  |  |  |  |  | } | 
| 182 | 0 | 0 |  |  |  |  | for (ch = 0; ch < 3; ++ch) { | 
| 183 | 0 | 0 |  |  |  |  | if (tcolorp->cf1.channel[ch] > tcolorp->cf2.channel[ch]) | 
| 184 | 0 |  |  |  |  |  | break; | 
| 185 |  |  |  |  |  |  | } | 
| 186 | 0 | 0 |  |  |  |  | if (ch == 3) { | 
| 187 | 0 |  |  |  |  |  | ++tcolorp, ++tcolor_count; | 
| 188 |  |  |  |  |  |  | } | 
| 189 |  |  |  |  |  |  | } | 
| 190 |  |  |  |  |  |  | /* TODO optimize where the image is greyscale to remove color ranges that don't | 
| 191 |  |  |  |  |  |  | overlap the greyscale line | 
| 192 |  |  |  |  |  |  | */ | 
| 193 |  |  |  |  |  |  | } | 
| 194 |  |  |  |  |  |  | } | 
| 195 |  |  |  |  |  |  |  | 
| 196 | 12 |  |  |  |  |  | i_clear_error(); | 
| 197 |  |  |  |  |  |  |  | 
| 198 | 12 | 50 |  |  |  |  | if (transp_threshold > 1.0 && tcolor_count == 0) { | 
|  |  | 0 |  |  |  |  |  | 
| 199 |  |  |  |  |  |  | /* nothing to do */ | 
| 200 | 0 |  |  |  |  |  | *left = *top = *right = *bottom = 0; | 
| 201 | 0 |  |  |  |  |  | result = 1; | 
| 202 |  |  |  |  |  |  | } | 
| 203 |  |  |  |  |  |  | else { | 
| 204 | 12 |  |  |  |  |  | result = trim_rect_simple(im, transp_threshold, tcolor_count, tcolors, left, top, | 
| 205 |  |  |  |  |  |  | right, bottom); | 
| 206 |  |  |  |  |  |  | } | 
| 207 |  |  |  |  |  |  |  | 
| 208 | 12 |  |  |  |  |  | myfree(tcolors); | 
| 209 | 12 |  |  |  |  |  | return result; | 
| 210 |  |  |  |  |  |  | } |