st

Kris's build of st
git clone git clone https://git.krisyotam.com/krisyotam/st.git
Log | Files | Refs | README | LICENSE

sixel.c (16625B)


      1 // sixel.c (part of mintty)
      2 // originally written by kmiya@cluti (https://github.com/saitoha/sixel/blob/master/fromsixel.c)
      3 // Licensed under the terms of the GNU General Public License v3 or later.
      4 
      5 #include <stdlib.h>
      6 #include <string.h>  /* memcpy */
      7 
      8 #include "st.h"
      9 #include "win.h"
     10 #include "sixel.h"
     11 #include "sixel_hls.h"
     12 
     13 #define SIXEL_RGB(r, g, b) ((255 << 24) + ((r) << 16) + ((g) << 8) +  (b))
     14 #define SIXEL_PALVAL(n,a,m) (((n) * (a) + ((m) / 2)) / (m))
     15 #define SIXEL_XRGB(r,g,b) SIXEL_RGB(SIXEL_PALVAL(r, 255, 100), SIXEL_PALVAL(g, 255, 100), SIXEL_PALVAL(b, 255, 100))
     16 
     17 static sixel_color_t const sixel_default_color_table[] = {
     18 	SIXEL_XRGB( 0,  0,  0),  /*  0 Black    */
     19 	SIXEL_XRGB(20, 20, 80),  /*  1 Blue     */
     20 	SIXEL_XRGB(80, 13, 13),  /*  2 Red      */
     21 	SIXEL_XRGB(20, 80, 20),  /*  3 Green    */
     22 	SIXEL_XRGB(80, 20, 80),  /*  4 Magenta  */
     23 	SIXEL_XRGB(20, 80, 80),  /*  5 Cyan     */
     24 	SIXEL_XRGB(80, 80, 20),  /*  6 Yellow   */
     25 	SIXEL_XRGB(53, 53, 53),  /*  7 Gray 50% */
     26 	SIXEL_XRGB(26, 26, 26),  /*  8 Gray 25% */
     27 	SIXEL_XRGB(33, 33, 60),  /*  9 Blue*    */
     28 	SIXEL_XRGB(60, 26, 26),  /* 10 Red*     */
     29 	SIXEL_XRGB(33, 60, 33),  /* 11 Green*   */
     30 	SIXEL_XRGB(60, 33, 60),  /* 12 Magenta* */
     31 	SIXEL_XRGB(33, 60, 60),  /* 13 Cyan*    */
     32 	SIXEL_XRGB(60, 60, 33),  /* 14 Yellow*  */
     33 	SIXEL_XRGB(80, 80, 80),  /* 15 Gray 75% */
     34 };
     35 
     36 void
     37 scroll_images(int n) {
     38 	ImageList *im, *next;
     39 	#if SCROLLBACK_PATCH || REFLOW_PATCH
     40 	int top = tisaltscr() ? 0 : term.scr - HISTSIZE;
     41 	#else
     42 	int top = 0;
     43 	#endif // SCROLLBACK_PATCH
     44 
     45 	for (im = term.images; im; im = next) {
     46 		next = im->next;
     47 		im->y += n;
     48 
     49 		/* check if the current sixel has exceeded the maximum
     50 		 * draw distance, and should therefore be deleted */
     51 		if (im->y < top) {
     52 			//fprintf(stderr, "im@0x%08x exceeded maximum distance\n");
     53 			delete_image(im);
     54 		}
     55 	}
     56 }
     57 
     58 void
     59 delete_image(ImageList *im)
     60 {
     61 	if (im->prev)
     62 		im->prev->next = im->next;
     63 	else
     64 		term.images = im->next;
     65 	if (im->next)
     66 		im->next->prev = im->prev;
     67 	if (im->pixmap)
     68 		XFreePixmap(xw.dpy, (Drawable)im->pixmap);
     69 	if (im->clipmask)
     70 		XFreePixmap(xw.dpy, (Drawable)im->clipmask);
     71 	free(im->pixels);
     72 	free(im);
     73 }
     74 
     75 static int
     76 set_default_color(sixel_image_t *image)
     77 {
     78 	int i;
     79 	int n;
     80 	int r;
     81 	int g;
     82 	int b;
     83 
     84 	/* palette initialization */
     85 	for (n = 1; n < 17; n++) {
     86 		image->palette[n] = sixel_default_color_table[n - 1];
     87 	}
     88 
     89 	/* colors 17-232 are a 6x6x6 color cube */
     90 	for (r = 0; r < 6; r++) {
     91 		for (g = 0; g < 6; g++) {
     92 			for (b = 0; b < 6; b++) {
     93 				image->palette[n++] = SIXEL_RGB(r * 51, g * 51, b * 51);
     94 			}
     95 		}
     96 	}
     97 
     98 	/* colors 233-256 are a grayscale ramp, intentionally leaving out */
     99 	for (i = 0; i < 24; i++) {
    100 		image->palette[n++] = SIXEL_RGB(i * 11, i * 11, i * 11);
    101 	}
    102 
    103 	/* sixels rarely use more than 256 colors and if they do, they use a custom
    104 	 * palette, so we don't need to initialize these colors */
    105 	/*
    106 	for (; n < DECSIXEL_PALETTE_MAX; n++) {
    107 		image->palette[n] = SIXEL_RGB(255, 255, 255);
    108 	}
    109 	*/
    110 
    111 	return (0);
    112 }
    113 
    114 static int
    115 sixel_image_init(
    116     sixel_image_t    *image,
    117     int              width,
    118     int              height,
    119     int              fgcolor,
    120     int              bgcolor,
    121     int              use_private_register)
    122 {
    123 	int status = (-1);
    124 	size_t size;
    125 
    126 	size = (size_t)(width * height) * sizeof(sixel_color_no_t);
    127 	image->width = width;
    128 	image->height = height;
    129 	image->data = (sixel_color_no_t *)malloc(size);
    130 	image->ncolors = 2;
    131 	image->use_private_register = use_private_register;
    132 
    133 	if (image->data == NULL) {
    134 		status = (-1);
    135 		goto end;
    136 	}
    137 	memset(image->data, 0, size);
    138 
    139 	image->palette[0] = bgcolor;
    140 
    141 	if (image->use_private_register)
    142 		image->palette[1] = fgcolor;
    143 
    144 	image->palette_modified = 0;
    145 
    146 	status = (0);
    147 
    148 end:
    149 	return status;
    150 }
    151 
    152 
    153 static int
    154 image_buffer_resize(
    155     sixel_image_t   *image,
    156     int              width,
    157     int              height)
    158 {
    159 	int status = (-1);
    160 	size_t size;
    161 	sixel_color_no_t *alt_buffer;
    162 	int n;
    163 	int min_height;
    164 
    165 	size = (size_t)(width * height) * sizeof(sixel_color_no_t);
    166 	alt_buffer = (sixel_color_no_t *)malloc(size);
    167 	if (alt_buffer == NULL) {
    168 		/* free source image */
    169 		free(image->data);
    170 		image->data = NULL;
    171 		status = (-1);
    172 		goto end;
    173 	}
    174 
    175 	min_height = height > image->height ? image->height: height;
    176 	if (width > image->width) {  /* if width is extended */
    177 		for (n = 0; n < min_height; ++n) {
    178 			/* copy from source image */
    179 			memcpy(alt_buffer + width * n,
    180 			       image->data + image->width * n,
    181 			       (size_t)image->width * sizeof(sixel_color_no_t));
    182 			/* fill extended area with background color */
    183 			memset(alt_buffer + width * n + image->width,
    184 			       0,
    185 			       (size_t)(width - image->width) * sizeof(sixel_color_no_t));
    186 		}
    187 	} else {
    188 		for (n = 0; n < min_height; ++n) {
    189 			/* copy from source image */
    190 			memcpy(alt_buffer + width * n,
    191 			       image->data + image->width * n,
    192 			       (size_t)width * sizeof(sixel_color_no_t));
    193 		}
    194 	}
    195 
    196 	if (height > image->height) {  /* if height is extended */
    197 		/* fill extended area with background color */
    198 		memset(alt_buffer + width * image->height,
    199 		       0,
    200 		       (size_t)(width * (height - image->height)) * sizeof(sixel_color_no_t));
    201 	}
    202 
    203 	/* free source image */
    204 	free(image->data);
    205 
    206 	image->data = alt_buffer;
    207 	image->width = width;
    208 	image->height = height;
    209 
    210 	status = (0);
    211 
    212 end:
    213 	return status;
    214 }
    215 
    216 static void
    217 sixel_image_deinit(sixel_image_t *image)
    218 {
    219 	if (image->data)
    220 		free(image->data);
    221 	image->data = NULL;
    222 }
    223 
    224 int
    225 sixel_parser_init(sixel_state_t *st,
    226                   int transparent,
    227                   sixel_color_t fgcolor, sixel_color_t bgcolor,
    228                   unsigned char use_private_register,
    229                   int cell_width, int cell_height)
    230 {
    231 	int status = (-1);
    232 
    233 	st->state = PS_DECSIXEL;
    234 	st->pos_x = 0;
    235 	st->pos_y = 0;
    236 	st->max_x = 0;
    237 	st->max_y = 0;
    238 	st->attributed_pan = 2;
    239 	st->attributed_pad = 1;
    240 	st->attributed_ph = 0;
    241 	st->attributed_pv = 0;
    242 	st->transparent = transparent;
    243 	st->repeat_count = 1;
    244 	st->color_index = 16;
    245 	st->grid_width = cell_width;
    246 	st->grid_height = cell_height;
    247 	st->nparams = 0;
    248 	st->param = 0;
    249 
    250 	/* buffer initialization */
    251 	status = sixel_image_init(&st->image, 1, 1, fgcolor, transparent ? 0 : bgcolor, use_private_register);
    252 
    253 	return status;
    254 }
    255 
    256 int
    257 sixel_parser_set_default_color(sixel_state_t *st)
    258 {
    259 	return set_default_color(&st->image);
    260 }
    261 
    262 int
    263 sixel_parser_finalize(sixel_state_t *st, ImageList **newimages, int cx, int cy, int cw, int ch)
    264 {
    265 	sixel_image_t *image = &st->image;
    266 	int x, y;
    267 	sixel_color_no_t *src;
    268 	sixel_color_t *dst, color;
    269 	int w, h;
    270 	int i, j, cols, numimages;
    271 	char trans;
    272 	ImageList *im, *next, *tail;
    273 
    274 	if (!image->data)
    275 		return -1;
    276 
    277 	if (++st->max_x < st->attributed_ph)
    278 		st->max_x = st->attributed_ph;
    279 
    280 	if (++st->max_y < st->attributed_pv)
    281 		st->max_y = st->attributed_pv;
    282 
    283 	if (image->use_private_register && image->ncolors > 2 && !image->palette_modified) {
    284 		if (set_default_color(image) < 0)
    285 			return -1;
    286 	}
    287 
    288 	w = MIN(st->max_x, image->width);
    289 	h = MIN(st->max_y, image->height);
    290 
    291 	if ((numimages = (h + ch-1) / ch) <= 0)
    292 		return -1;
    293 
    294 	cols = (w + cw-1) / cw;
    295 
    296 	*newimages = NULL, tail = NULL;
    297 	for (y = 0, i = 0; i < numimages; i++) {
    298 		if ((im = malloc(sizeof(ImageList)))) {
    299 			if (!tail) {
    300 				*newimages = tail = im;
    301 				im->prev = im->next = NULL;
    302 			} else {
    303 				tail->next = im;
    304 				im->prev = tail;
    305 				im->next = NULL;
    306 				tail = im;
    307 			}
    308 			im->x = cx;
    309 			im->y = cy + i;
    310 			im->cols = cols;
    311 			im->width = w;
    312 			im->height = MIN(h - ch * i, ch);
    313 			im->pixels = malloc(im->width * im->height * 4);
    314 			im->pixmap = NULL;
    315 			im->clipmask = NULL;
    316 			im->cw = cw;
    317 			im->ch = ch;
    318 		}
    319 		if (!im || !im->pixels) {
    320 			for (im = *newimages; im; im = next) {
    321 				next = im->next;
    322 				if (im->pixels)
    323 					free(im->pixels);
    324 				free(im);
    325 			}
    326 			*newimages = NULL;
    327 			return -1;
    328 		}
    329 		dst = (sixel_color_t *)im->pixels;
    330 		for (trans = 0, j = 0; j < im->height && y < h; j++, y++) {
    331 			src = st->image.data + image->width * y;
    332 			for (x = 0; x < w; x++) {
    333 				color = st->image.palette[*src++];
    334 				trans |= (color == 0);
    335 				*dst++ = color;
    336 			}
    337 		}
    338 		im->transparent = (st->transparent && trans);
    339 	}
    340 
    341 	return numimages;
    342 }
    343 
    344 /* convert sixel data into indexed pixel bytes and palette data */
    345 int
    346 sixel_parser_parse(sixel_state_t *st, const unsigned char *p, size_t len)
    347 {
    348 	int n = 0;
    349 	int i;
    350 	int x;
    351 	int y;
    352 	int bits;
    353 	int sx;
    354 	int sy;
    355 	int c;
    356 	int pos;
    357 	int width;
    358 	const unsigned char *p0 = p, *p2 = p + len;
    359 	sixel_image_t *image = &st->image;
    360 	sixel_color_no_t *data, color_index;
    361 
    362 	if (!image->data)
    363 		st->state = PS_ERROR;
    364 
    365 	while (p < p2) {
    366 		switch (st->state) {
    367 		case PS_ESC:
    368 			goto end;
    369 
    370 		case PS_DECSIXEL:
    371 			switch (*p) {
    372 			case '\x1b':
    373 				st->state = PS_ESC;
    374 				break;
    375 			case '"':
    376 				st->param = 0;
    377 				st->nparams = 0;
    378 				st->state = PS_DECGRA;
    379 				p++;
    380 				break;
    381 			case '!':
    382 				st->param = 0;
    383 				st->nparams = 0;
    384 				st->state = PS_DECGRI;
    385 				p++;
    386 				break;
    387 			case '#':
    388 				st->param = 0;
    389 				st->nparams = 0;
    390 				st->state = PS_DECGCI;
    391 				p++;
    392 				break;
    393 			case '$':
    394 				/* DECGCR Graphics Carriage Return */
    395 				st->pos_x = 0;
    396 				p++;
    397 				break;
    398 			case '-':
    399 				/* DECGNL Graphics Next Line */
    400 				st->pos_x = 0;
    401 				if (st->pos_y < DECSIXEL_HEIGHT_MAX - 5 - 6)
    402 					st->pos_y += 6;
    403 				else
    404 					st->pos_y = DECSIXEL_HEIGHT_MAX + 1;
    405 				p++;
    406 				break;
    407 			default:
    408 				if (*p >= '?' && *p <= '~') {  /* sixel characters */
    409 					if ((image->width < (st->pos_x + st->repeat_count) || image->height < (st->pos_y + 6))
    410 					        && image->width < DECSIXEL_WIDTH_MAX && image->height < DECSIXEL_HEIGHT_MAX) {
    411 						sx = image->width * 2;
    412 						sy = image->height * 2;
    413 						while (sx < (st->pos_x + st->repeat_count) || sy < (st->pos_y + 6)) {
    414 							sx *= 2;
    415 							sy *= 2;
    416 						}
    417 
    418 						sx = MIN(sx, DECSIXEL_WIDTH_MAX);
    419 						sy = MIN(sy, DECSIXEL_HEIGHT_MAX);
    420 
    421 						if (image_buffer_resize(image, sx, sy) < 0) {
    422 							perror("sixel_parser_parse() failed");
    423 							st->state = PS_ERROR;
    424 							p++;
    425 							break;
    426 						}
    427 					}
    428 
    429 					if (st->color_index > image->ncolors)
    430 						image->ncolors = st->color_index;
    431 
    432 					if (st->pos_x + st->repeat_count > image->width)
    433 						st->repeat_count = image->width - st->pos_x;
    434 
    435 					if (st->repeat_count > 0 && st->pos_y + 5 < image->height) {
    436 						bits = *p - '?';
    437 						if (bits != 0) {
    438 							data = image->data + image->width * st->pos_y + st->pos_x;
    439 							width = image->width;
    440 							color_index = st->color_index;
    441 							if (st->repeat_count <= 1) {
    442 								if (bits & 0x01)
    443 									*data = color_index, n = 0;
    444 								data += width;
    445 								if (bits & 0x02)
    446 									*data = color_index, n = 1;
    447 								data += width;
    448 								if (bits & 0x04)
    449 									*data = color_index, n = 2;
    450 								data += width;
    451 								if (bits & 0x08)
    452 									*data = color_index, n = 3;
    453 								data += width;
    454 								if (bits & 0x10)
    455 									*data = color_index, n = 4;
    456 								if (bits & 0x20)
    457 									data[width] = color_index, n = 5;
    458 								if (st->max_x < st->pos_x)
    459 									st->max_x = st->pos_x;
    460 							} else {
    461 								/* st->repeat_count > 1 */
    462 								for (i = 0; bits; bits >>= 1, i++, data += width) {
    463 									if (bits & 1) {
    464 										data[0] = color_index;
    465 										data[1] = color_index;
    466 										for (x = 2; x < st->repeat_count; x++)
    467 											data[x] = color_index;
    468 										n = i;
    469 									}
    470 								}
    471 								if (st->max_x < (st->pos_x + st->repeat_count - 1))
    472 									st->max_x = st->pos_x + st->repeat_count - 1;
    473 							}
    474 							if (st->max_y < (st->pos_y + n))
    475 								st->max_y = st->pos_y + n;
    476 						}
    477 					}
    478 					if (st->repeat_count > 0)
    479 						st->pos_x += st->repeat_count;
    480 					st->repeat_count = 1;
    481 				}
    482 				p++;
    483 				break;
    484 			}
    485 			break;
    486 
    487 		case PS_DECGRA:
    488 			/* DECGRA Set Raster Attributes " Pan; Pad; Ph; Pv */
    489 			switch (*p) {
    490 			case '\x1b':
    491 				st->state = PS_ESC;
    492 				break;
    493 			case '0':
    494 			case '1':
    495 			case '2':
    496 			case '3':
    497 			case '4':
    498 			case '5':
    499 			case '6':
    500 			case '7':
    501 			case '8':
    502 			case '9':
    503 				st->param = st->param * 10 + *p - '0';
    504 				st->param = MIN(st->param, DECSIXEL_PARAMVALUE_MAX);
    505 				p++;
    506 				break;
    507 			case ';':
    508 				if (st->nparams < DECSIXEL_PARAMS_MAX)
    509 					st->params[st->nparams++] = st->param;
    510 				st->param = 0;
    511 				p++;
    512 				break;
    513 			default:
    514 				if (st->nparams < DECSIXEL_PARAMS_MAX)
    515 					st->params[st->nparams++] = st->param;
    516 				if (st->nparams > 0)
    517 					st->attributed_pad = st->params[0];
    518 				if (st->nparams > 1)
    519 					st->attributed_pan = st->params[1];
    520 				if (st->nparams > 2 && st->params[2] > 0)
    521 					st->attributed_ph = st->params[2];
    522 				if (st->nparams > 3 && st->params[3] > 0)
    523 					st->attributed_pv = st->params[3];
    524 
    525 				if (st->attributed_pan <= 0)
    526 					st->attributed_pan = 1;
    527 				if (st->attributed_pad <= 0)
    528 					st->attributed_pad = 1;
    529 
    530 				if (image->width < st->attributed_ph ||
    531 				        image->height < st->attributed_pv) {
    532 					sx = MAX(image->width, st->attributed_ph);
    533 					sy = MAX(image->height, st->attributed_pv);
    534 
    535 					/* the height of the image buffer must be divisible by 6
    536 					 * to avoid unnecessary resizing of the image buffer when
    537 					 * parsing the last sixel line */
    538 					sy = (sy + 5) / 6 * 6;
    539 
    540 					sx = MIN(sx, DECSIXEL_WIDTH_MAX);
    541 					sy = MIN(sy, DECSIXEL_HEIGHT_MAX);
    542 
    543 					if (image_buffer_resize(image, sx, sy) < 0) {
    544 						perror("sixel_parser_parse() failed");
    545 						st->state = PS_ERROR;
    546 						break;
    547 					}
    548 				}
    549 				st->state = PS_DECSIXEL;
    550 				st->param = 0;
    551 				st->nparams = 0;
    552 			}
    553 			break;
    554 
    555 		case PS_DECGRI:
    556 			/* DECGRI Graphics Repeat Introducer ! Pn Ch */
    557 			switch (*p) {
    558 			case '\x1b':
    559 				st->state = PS_ESC;
    560 				break;
    561 			case '0':
    562 			case '1':
    563 			case '2':
    564 			case '3':
    565 			case '4':
    566 			case '5':
    567 			case '6':
    568 			case '7':
    569 			case '8':
    570 			case '9':
    571 				st->param = st->param * 10 + *p - '0';
    572 				st->param = MIN(st->param, DECSIXEL_PARAMVALUE_MAX);
    573 				p++;
    574 				break;
    575 			default:
    576 				st->repeat_count = MAX(st->param, 1);
    577 				st->state = PS_DECSIXEL;
    578 				st->param = 0;
    579 				st->nparams = 0;
    580 				break;
    581 			}
    582 			break;
    583 
    584 		case PS_DECGCI:
    585 			/* DECGCI Graphics Color Introducer # Pc; Pu; Px; Py; Pz */
    586 			switch (*p) {
    587 			case '\x1b':
    588 				st->state = PS_ESC;
    589 				break;
    590 			case '0':
    591 			case '1':
    592 			case '2':
    593 			case '3':
    594 			case '4':
    595 			case '5':
    596 			case '6':
    597 			case '7':
    598 			case '8':
    599 			case '9':
    600 				st->param = st->param * 10 + *p - '0';
    601 				st->param = MIN(st->param, DECSIXEL_PARAMVALUE_MAX);
    602 				p++;
    603 				break;
    604 			case ';':
    605 				if (st->nparams < DECSIXEL_PARAMS_MAX)
    606 					st->params[st->nparams++] = st->param;
    607 				st->param = 0;
    608 				p++;
    609 				break;
    610 			default:
    611 				st->state = PS_DECSIXEL;
    612 				if (st->nparams < DECSIXEL_PARAMS_MAX)
    613 					st->params[st->nparams++] = st->param;
    614 				st->param = 0;
    615 
    616 				if (st->nparams > 0) {
    617 					st->color_index = st->params[0];
    618 					if (st->color_index < 0)
    619 						st->color_index = 0;
    620 					else if (st->color_index >= DECSIXEL_PALETTE_MAX)
    621 						st->color_index = DECSIXEL_PALETTE_MAX - 1;
    622 					st->color_index++; /* offset by 1 (background) */
    623 				}
    624 
    625 				if (st->nparams > 4) {
    626 					st->image.palette_modified = 1;
    627 					if (st->params[1] == 1) {
    628 						/* HLS */
    629 						st->params[2] = MIN(st->params[2], 360);
    630 						st->params[3] = MIN(st->params[3], 100);
    631 						st->params[4] = MIN(st->params[4], 100);
    632 						image->palette[st->color_index]
    633 						    = hls_to_rgb(st->params[2], st->params[3], st->params[4]);
    634 					} else if (st->params[1] == 2) {
    635 						/* RGB */
    636 						st->params[2] = MIN(st->params[2], 100);
    637 						st->params[3] = MIN(st->params[3], 100);
    638 						st->params[4] = MIN(st->params[4], 100);
    639 						image->palette[st->color_index]
    640 						    = SIXEL_XRGB(st->params[2], st->params[3], st->params[4]);
    641 					}
    642 				}
    643 				break;
    644 			}
    645 			break;
    646 
    647 		case PS_ERROR:
    648 			if (*p == '\x1b') {
    649 				st->state = PS_ESC;
    650 				goto end;
    651 			}
    652 			p++;
    653 			break;
    654 		default:
    655 			break;
    656 		}
    657 	}
    658 
    659 end:
    660 	return p - p0;
    661 }
    662 
    663 void
    664 sixel_parser_deinit(sixel_state_t *st)
    665 {
    666 	if (st)
    667 		sixel_image_deinit(&st->image);
    668 }
    669 
    670 Pixmap
    671 sixel_create_clipmask(char *pixels, int width, int height)
    672 {
    673 	char c, *clipdata, *dst;
    674 	int b, i, n, y, w;
    675 	int msb = (XBitmapBitOrder(xw.dpy) == MSBFirst);
    676 	sixel_color_t *src = (sixel_color_t *)pixels;
    677 	Pixmap clipmask;
    678 
    679 	clipdata = dst = malloc((width+7)/8 * height);
    680 	if (!clipdata)
    681 		return (Pixmap)None;
    682 
    683 	for (y = 0; y < height; y++) {
    684 		for (w = width; w > 0; w -= n) {
    685 			n = MIN(w, 8);
    686 			if (msb) {
    687 				for (b = 0x80, c = 0, i = 0; i < n; i++, b >>= 1)
    688 					c |= (*src++) ? b : 0;
    689 			} else {
    690 				for (b = 0x01, c = 0, i = 0; i < n; i++, b <<= 1)
    691 					c |= (*src++) ? b : 0;
    692 			}
    693 			*dst++ = c;
    694 		}
    695 	}
    696 
    697 	clipmask = XCreateBitmapFromData(xw.dpy, xw.win, clipdata, width, height);
    698 	free(clipdata);
    699 	return clipmask;
    700 }