12 static int clamp[CLAMPOFF+256+CLAMPOFF];
16 _remaperror(char *fmt, ...)
22 vseprint(buf, buf+sizeof buf, fmt, arg);
30 torgbv(Rawimage *i, int errdiff)
32 int j, k, rgb, x, y, er, eg, eb, col, t;
33 int r, g, b, r1, g1, b1;
34 int *ered, *egrn, *eblu, *rp, *gp, *bp;
40 uchar *cmap, *cm, *in, *out, *inp, *outp, cmap1[3*256], map[256], *rpic, *bpic, *gpic;
43 errstr(err, sizeof err); /* throw it away */
44 im = malloc(sizeof(Rawimage));
47 memset(im, 0, sizeof(Rawimage));
48 im->chans[0] = malloc(i->chanlen);
49 if(im->chans[0] == nil){
56 im->chanlen = i->chanlen;
58 dx = i->r.max.x-i->r.min.x;
59 dy = i->r.max.y-i->r.min.y;
64 for(j=0; j<CLAMPOFF; j++)
67 clamp[CLAMPOFF+j] = (j>>4);
68 for(j=0; j<CLAMPOFF; j++)
69 clamp[CLAMPOFF+256+j] = (255>>4);
77 ered = malloc((dx+1)*sizeof(int));
78 egrn = malloc((dx+1)*sizeof(int));
79 eblu = malloc((dx+1)*sizeof(int));
80 if(ered==nil || egrn==nil || eblu==nil){
86 return _remaperror("remap: malloc failed: %r");
88 memset(ered, 0, (dx+1)*sizeof(int));
89 memset(egrn, 0, (dx+1)*sizeof(int));
90 memset(eblu, 0, (dx+1)*sizeof(int));
94 return _remaperror("remap: can't recognize channel type %d", i->chandesc);
97 return _remaperror("remap: image has no color map");
99 return _remaperror("remap: can't handle nchans %d", i->nchans);
101 if(i->cmaplen == 3*(1<<j))
104 return _remaperror("remap: can't do colormap size 3*%d", i->cmaplen/3);
105 if(i->cmaplen != 3*256){
106 /* to avoid a range check in inner loop below, make a full-size cmap */
107 memmove(cmap1, cmap, i->cmaplen);
112 for(j=0; j<256; j++){
117 map[j] = closestrgb[b+16*(g+16*r)];
119 for(j=0; j<i->chanlen; j++)
122 /* modified floyd steinberg, coefficients (1 0) 3/16, (0, 1) 3/16, (1, 1) 7/16 */
131 cm = &cmap[3 * *inp++];
136 /* sanity checks are new */
137 if(r >= 256+CLAMPOFF)
139 if(g >= 256+CLAMPOFF)
141 if(b >= 256+CLAMPOFF)
143 r1 = clamp[r+CLAMPOFF];
144 g1 = clamp[g+CLAMPOFF];
145 b1 = clamp[b+CLAMPOFF];
146 if(r1 >= 16 || g1 >= 16 || b1 >= 16)
149 col = closestrgb[b1+16*(g1+16*r1)];
153 r -= (rgb>>16) & 0xFF;
159 g -= (rgb>>8) & 0xFF;
176 closest = closestycbcr;
181 closest = closestrgb;
186 return _remaperror("remap: RGB image has %d channels", i->nchans);
191 for(j=0; j<i->chanlen; j++){
195 out[j] = closest[b+16*(g+16*r)];
198 /* modified floyd steinberg, coefficients (1 0) 3/16, (0, 1) 3/16, (1, 1) 7/16 */
211 * Errors can be uncorrectable if converting from YCbCr,
212 * since we can't guarantee that an extremal value of one of
213 * the components selects a color with an extremal value.
214 * If we don't, the errors accumulate without bound. This
215 * doesn't happen in RGB because the closest table can guarantee
216 * a color on the edge of the gamut, producing a zero error in
217 * that component. For the rotation YCbCr space, there may be
218 * no color that can guarantee zero error at the edge.
219 * Therefore we must clamp explicitly rather than by assuming
220 * an upper error bound of CLAMPOFF. The performance difference
221 * is miniscule anyway.
238 col = closest[b1+16*(g1+16*r1)];
242 r -= (rgb>>16) & 0xFF;
248 g -= (rgb>>8) & 0xFF;
266 return _remaperror("remap: Y image has %d chans", i->nchans);
269 for(j=0; j<i->chanlen; j++){
271 *outp++ = closestrgb[r+16*(r+16*r)];
274 /* modified floyd steinberg, coefficients (1 0) 3/16, (0, 1) 3/16, (1, 1) 7/16 */
280 r1 = clamp[r+CLAMPOFF];
281 col = closestrgb[r1+16*(r1+16*r1)];
285 r -= (rgb>>16) & 0xFF;