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