1 /* Copyright © 2007 Bart Massey
3 * Permission is hereby granted, free of charge, to any person obtaining a
4 * copy of this software and associated documentation files (the "Software"),
5 * to deal in the Software without restriction, including without limitation
6 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
7 * and/or sell copies of the Software, and to permit persons to whom the
8 * Software is furnished to do so, subject to the following conditions:
10 * The above copyright notice and this permission notice shall be included in
11 * all copies or substantial portions of the Software.
13 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16 * AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
17 * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
18 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
20 * Except as contained in this notice, the names of the authors or their
21 * institutions shall not be used in advertising or otherwise to promote the
22 * sale, use or other dealings in this Software without prior written
23 * authorization from the authors.
32 #include "../aux/xcb_aux.h"
33 #include "../aux/xcb_bitops.h"
34 #include "xcb_image.h"
36 #include "xcb_pixel.h"
40 find_format_by_depth (const xcb_setup_t *setup, uint8_t depth)
42 xcb_format_t *fmt = xcb_setup_pixmap_formats(setup);
43 xcb_format_t *fmtend = fmt + xcb_setup_pixmap_formats_length(setup);
44 for(; fmt != fmtend; ++fmt)
45 if(fmt->depth == depth)
51 static xcb_image_format_t
52 effective_format(xcb_image_format_t format, uint8_t bpp)
54 if (format == XCB_IMAGE_FORMAT_Z_PIXMAP && bpp != 1)
56 return XCB_IMAGE_FORMAT_XY_PIXMAP;
61 format_valid (uint8_t depth, uint8_t bpp, uint8_t unit,
62 xcb_image_format_t format, uint8_t xpad)
64 xcb_image_format_t ef = effective_format(format, bpp);
68 case XCB_IMAGE_FORMAT_XY_PIXMAP:
88 case XCB_IMAGE_FORMAT_Z_PIXMAP:
113 image_format_valid (xcb_image_t *image) {
114 return format_valid(image->depth,
118 image->scanline_pad);
123 xcb_image_annotate (xcb_image_t *image)
125 xcb_image_format_t ef = effective_format(image->format, image->bpp);
127 case XCB_IMAGE_FORMAT_XY_PIXMAP:
128 image->stride = xcb_roundup(image->width, image->scanline_pad) >> 3;
129 image->size = image->height * image->stride * image->depth;
131 case XCB_IMAGE_FORMAT_Z_PIXMAP:
132 image->stride = xcb_roundup((uint32_t)image->width *
133 (uint32_t)image->bpp,
134 image->scanline_pad) >> 3;
135 image->size = image->height * image->stride;
144 xcb_image_create_native (xcb_connection_t * c,
147 xcb_image_format_t format,
153 const xcb_setup_t * setup = xcb_get_setup(c);
155 xcb_image_format_t ef = format;
157 if (ef == XCB_IMAGE_FORMAT_Z_PIXMAP && depth == 1)
158 ef = XCB_IMAGE_FORMAT_XY_PIXMAP;
160 case XCB_IMAGE_FORMAT_XY_BITMAP:
164 case XCB_IMAGE_FORMAT_XY_PIXMAP:
166 fmt = find_format_by_depth(setup, depth);
170 return xcb_image_create(width, height, format,
171 setup->bitmap_format_scanline_pad,
172 depth, depth, setup->bitmap_format_scanline_unit,
173 setup->image_byte_order,
174 setup->bitmap_format_bit_order,
176 case XCB_IMAGE_FORMAT_Z_PIXMAP:
177 fmt = find_format_by_depth(setup, depth);
180 return xcb_image_create(width, height, format,
182 fmt->depth, fmt->bits_per_pixel, 0,
183 setup->image_byte_order,
184 XCB_IMAGE_ORDER_MSB_FIRST,
194 xcb_image_create (uint16_t width,
196 xcb_image_format_t format,
201 xcb_image_order_t byte_order,
202 xcb_image_order_t bit_order,
211 case XCB_IMAGE_FORMAT_XY_BITMAP:
212 case XCB_IMAGE_FORMAT_XY_PIXMAP:
215 case XCB_IMAGE_FORMAT_Z_PIXMAP:
228 if (!format_valid(depth, bpp, unit, format, xpad))
230 image = malloc(sizeof(*image));
233 image->width = width;
234 image->height = height;
235 image->format = format;
236 image->scanline_pad = xpad;
237 image->depth = depth;
240 image->plane_mask = xcb_mask(depth);
241 image->byte_order = byte_order;
242 image->bit_order = bit_order;
243 xcb_image_annotate(image);
246 * Ways this function can be called:
247 * * with data: we fail if bytes isn't
248 * large enough, else leave well enough alone.
249 * * with base and !data: if bytes is zero, we
250 * default; otherwise we fail if bytes isn't
251 * large enough, else fill in data
252 * * with !base and !data: we malloc storage
253 * for the data, save that address as the base,
254 * and fail if malloc does.
256 * When successful, we establish the invariant that data
257 * points at sufficient storage that may have been
258 * supplied, and base is set iff it should be
259 * auto-freed when the image is destroyed.
261 * Except as a special case when base = 0 && data == 0 &&
262 * bytes == ~0 we just return the image structure and let
263 * the caller deal with getting the allocation right.
265 if (!base && !data && bytes == ~0) {
270 if (!base && data && bytes == 0)
276 image->data = image->base;
279 image->base = malloc(bytes);
280 image->data = image->base;
283 if (!image->data || bytes < image->size) {
292 xcb_image_destroy (xcb_image_t *image)
301 xcb_image_get (xcb_connection_t * conn,
308 xcb_image_format_t format)
310 xcb_get_image_cookie_t image_cookie;
311 xcb_get_image_reply_t * imrep;
312 xcb_image_t * image = 0;
316 image_cookie = xcb_get_image(conn, format, draw, x, y,
317 width, height, plane_mask);
318 imrep = xcb_get_image_reply(conn, image_cookie, 0);
321 bytes = xcb_get_image_data_length(imrep);
322 data = xcb_get_image_data(imrep);
324 case XCB_IMAGE_FORMAT_XY_PIXMAP:
325 plane_mask &= xcb_mask(imrep->depth);
326 if (plane_mask != xcb_mask(imrep->depth)) {
327 xcb_image_t * tmp_image =
328 xcb_image_create_native(conn, width, height, format,
329 imrep->depth, 0, 0, 0);
331 uint32_t rpm = plane_mask;
332 uint8_t * src_plane = image->data;
333 uint8_t * dst_plane = tmp_image->data;
334 uint32_t size = image->height * image->stride;
340 if (tmp_image->bit_order == XCB_IMAGE_ORDER_MSB_FIRST)
341 rpm = xcb_bit_reverse(plane_mask, imrep->depth);
342 for (i = 0; i < imrep->depth; i++) {
344 memcpy(dst_plane, src_plane, size);
347 memset(dst_plane, 0, size);
351 tmp_image->plane_mask = plane_mask;
357 case XCB_IMAGE_FORMAT_Z_PIXMAP:
358 image = xcb_image_create_native(conn, width, height, format,
359 imrep->depth, imrep, bytes, data);
368 assert(bytes == image->size);
374 xcb_image_native (xcb_connection_t * c,
378 xcb_image_t * tmp_image = 0;
379 const xcb_setup_t * setup = xcb_get_setup(c);
380 xcb_format_t * fmt = 0;
381 xcb_image_format_t ef = effective_format(image->format, image->bpp);
384 if (image->depth > 1 || ef == XCB_IMAGE_FORMAT_Z_PIXMAP) {
385 fmt = find_format_by_depth(setup, image->depth);
386 /* XXX For now, we don't do depth conversions, even
390 bpp = fmt->bits_per_pixel;
393 case XCB_IMAGE_FORMAT_XY_PIXMAP:
394 if (setup->bitmap_format_scanline_unit != image->unit ||
395 setup->bitmap_format_scanline_pad != image->scanline_pad ||
396 setup->image_byte_order != image->byte_order ||
397 setup->bitmap_format_bit_order != image->bit_order ||
402 xcb_image_create(image->width, image->height, image->format,
403 setup->bitmap_format_scanline_pad,
405 setup->bitmap_format_scanline_unit,
406 setup->image_byte_order,
407 setup->bitmap_format_bit_order,
413 case XCB_IMAGE_FORMAT_Z_PIXMAP:
414 if (fmt->scanline_pad != image->scanline_pad ||
415 setup->image_byte_order != image->byte_order ||
420 xcb_image_create(image->width, image->height, image->format,
422 image->depth, bpp, 0,
423 setup->image_byte_order,
424 XCB_IMAGE_ORDER_MSB_FIRST,
434 if (!xcb_image_convert(image, tmp_image)) {
435 xcb_image_destroy(tmp_image);
445 xcb_image_put (xcb_connection_t * conn,
453 return xcb_put_image(conn, image->format, draw, gc,
454 image->width, image->height,
468 xcb_image_shm_put (xcb_connection_t * conn,
472 xcb_shm_segment_info_t shminfo,
481 if (!xcb_image_native(conn, image, 0))
483 if (!shminfo.shmaddr)
485 xcb_shm_put_image(conn, draw, gc,
486 image->width, image->height,
487 src_x, src_y, src_width, src_height,
489 image->depth, image->format,
492 image->data - shminfo.shmaddr);
498 xcb_image_shm_get (xcb_connection_t * conn,
501 xcb_shm_segment_info_t shminfo,
506 xcb_shm_get_image_reply_t * setup;
507 xcb_shm_get_image_cookie_t cookie;
508 xcb_generic_error_t * err = 0;
510 if (!shminfo.shmaddr)
512 cookie = xcb_shm_get_image(conn, draw,
514 image->width, image->height,
518 image->data - shminfo.shmaddr);
519 setup = xcb_shm_get_image_reply(conn, cookie, &err);
521 fprintf(stderr, "ShmGetImageReply error %d\n", (int)err->error_code);
532 xy_image_byte (xcb_image_t *image, uint32_t x)
535 if (image->byte_order == image->bit_order)
537 switch (image->unit) {
549 xy_image_bit (xcb_image_t *image, uint32_t x)
552 if (image->bit_order == XCB_IMAGE_ORDER_MSB_FIRST)
557 /* GetPixel/PutPixel */
559 /* XXX this is the most hideously done cut-and-paste
560 to below. Any bugs fixed there should be fixed here
563 xcb_image_put_pixel (xcb_image_t *image,
570 if (x > image->width || y > image->height)
572 row = image->data + (y * image->stride);
573 switch (effective_format(image->format, image->bpp)) {
574 case XCB_IMAGE_FORMAT_XY_BITMAP:
575 case XCB_IMAGE_FORMAT_XY_PIXMAP:
578 uint32_t plane_mask = image->plane_mask;
579 uint8_t * plane = row;
580 uint32_t byte = xy_image_byte(image, x);
581 uint32_t bit = xy_image_bit(image,x);
582 uint8_t mask = 1 << bit;
584 for (p = image->bpp - 1; p >= 0; p--) {
585 if ((plane_mask >> p) & 1) {
586 uint8_t * bp = plane + byte;
587 uint8_t this_bit = ((pixel >> p) & 1) << bit;
588 *bp = (*bp & ~mask) | this_bit;
590 plane += image->stride * image->height;
594 case XCB_IMAGE_FORMAT_Z_PIXMAP:
595 switch (image->bpp) {
601 (image->byte_order == XCB_IMAGE_ORDER_MSB_FIRST)) {
605 row[x >> 1] = (row[x >> 1] & ~mask) | pixel;
611 switch (image->byte_order) {
612 case XCB_IMAGE_ORDER_LSB_FIRST:
614 row[(x << 1) + 1] = pixel >> 8;
616 case XCB_IMAGE_ORDER_MSB_FIRST:
617 row[x << 1] = pixel >> 8;
618 row[(x << 1) + 1] = pixel;
623 switch (image->byte_order) {
624 case XCB_IMAGE_ORDER_LSB_FIRST:
626 row[x * 3 + 1] = pixel >> 8;
627 row[x * 3 + 2] = pixel >> 16;
629 case XCB_IMAGE_ORDER_MSB_FIRST:
630 row[x * 3] = pixel >> 16;
631 row[x * 3 + 1] = pixel >> 8;
632 row[x * 3 + 2] = pixel;
637 switch (image->byte_order) {
638 case XCB_IMAGE_ORDER_LSB_FIRST:
640 row[(x << 2) + 1] = pixel >> 8;
641 row[(x << 2) + 2] = pixel >> 16;
642 row[(x << 2) + 3] = pixel >> 24;
644 case XCB_IMAGE_ORDER_MSB_FIRST:
645 row[x << 2] = pixel >> 24;
646 row[(x << 2) + 1] = pixel >> 16;
647 row[(x << 2) + 2] = pixel >> 8;
648 row[(x << 2) + 3] = pixel;
662 /* XXX this is the most hideously done cut-and-paste
663 from above. Any bugs fixed there should be fixed here
666 xcb_image_get_pixel (xcb_image_t *image,
673 assert(x < image->width && y < image->height);
674 row = image->data + (y * image->stride);
675 switch (effective_format(image->format, image->bpp)) {
676 case XCB_IMAGE_FORMAT_XY_BITMAP:
677 case XCB_IMAGE_FORMAT_XY_PIXMAP:
680 uint32_t plane_mask = image->plane_mask;
681 uint8_t * plane = row;
682 uint32_t byte = xy_image_byte(image, x);
683 uint32_t bit = xy_image_bit(image,x);
685 for (p = image->bpp - 1; p >= 0; p--) {
687 if ((plane_mask >> p) & 1) {
688 uint8_t * bp = plane + byte;
689 pixel |= (*bp >> bit) & 1;
691 plane += image->stride * image->height;
695 case XCB_IMAGE_FORMAT_Z_PIXMAP:
696 switch (image->bpp) {
698 if ((x & 1) == (image->byte_order == XCB_IMAGE_ORDER_MSB_FIRST))
699 return row[x >> 1] >> 4;
700 return row[x >> 1] & 0xf;
704 switch (image->byte_order) {
705 case XCB_IMAGE_ORDER_LSB_FIRST:
707 pixel |= row[(x << 1) + 1] << 8;
709 case XCB_IMAGE_ORDER_MSB_FIRST:
710 pixel = row[x << 1] << 8;
711 pixel |= row[(x << 1) + 1];
716 switch (image->byte_order) {
717 case XCB_IMAGE_ORDER_LSB_FIRST:
719 pixel |= row[x * 3 + 1] << 8;
720 pixel |= row[x * 3 + 2] << 16;
722 case XCB_IMAGE_ORDER_MSB_FIRST:
723 pixel = row[x * 3] << 16;
724 pixel |= row[x * 3 + 1] << 8;
725 pixel |= row[x * 3 + 2];
730 switch (image->byte_order) {
731 case XCB_IMAGE_ORDER_LSB_FIRST:
733 pixel |= row[(x << 2) + 1] << 8;
734 pixel |= row[(x << 2) + 2] << 16;
735 pixel |= row[(x << 2) + 3] << 24;
737 case XCB_IMAGE_ORDER_MSB_FIRST:
738 pixel = row[x << 2] << 24;
739 pixel |= row[(x << 2) + 1] << 16;
740 pixel |= row[(x << 2) + 2] << 8;
741 pixel |= row[(x << 2) + 3];
756 xcb_image_create_from_bitmap_data (uint8_t * data,
760 return xcb_image_create(width, height, XCB_IMAGE_FORMAT_XY_PIXMAP,
762 XCB_IMAGE_ORDER_LSB_FIRST,
763 XCB_IMAGE_ORDER_LSB_FIRST,
769 * (Adapted from libX11.)
771 * xcb_create_pixmap_from_bitmap_data: Routine to make a pixmap of
772 * given depth from user supplied bitmap data.
773 * D is any drawable on the same screen that the pixmap will be used in.
774 * Data is a pointer to the bit data, and
775 * width & height give the size in bits of the pixmap.
777 * The following format is assumed for data:
779 * format=XY (will use XYPixmap for depth 1 and XYBitmap for larger)
785 xcb_create_pixmap_from_bitmap_data (xcb_connection_t * display,
793 xcb_gcontext_t * gcp)
797 xcb_image_t * final_image;
802 image = xcb_image_create_from_bitmap_data(data, width, height);
806 image->format = XCB_IMAGE_FORMAT_XY_BITMAP;
807 final_image = xcb_image_native(display, image, 1);
809 xcb_image_destroy(image);
812 pix = xcb_generate_id(display);
813 xcb_create_pixmap(display, depth, pix, d, width, height);
814 gc = xcb_generate_id(display);
815 XCB_AUX_ADD_PARAM(&mask, &gcv, foreground, fg);
816 XCB_AUX_ADD_PARAM(&mask, &gcv, background, bg);
817 xcb_aux_create_gc(display, gc, pix, mask, &gcv);
818 xcb_image_put(display, pix, gc, final_image, 0, 0, 0);
819 if (final_image != image)
820 xcb_image_destroy(final_image);
821 xcb_image_destroy(image);
825 xcb_free_gc(display, gc);
830 /* Thanks to Keith Packard <keithp@keithp.com> for this code */
832 swap_image(uint8_t * src,
844 for (s = 0; s < src_stride; s++) {
846 uint32_t d = s ^ byteswap;
853 b = xcb_bit_reverse(b, 8);
855 b = (b << 4) | (b >> 4);
863 /* Which order are bytes in (low two bits), given
864 * code which accesses an image one byte at a time
867 byte_order(xcb_image_t *i)
869 uint32_t flip = i->byte_order == XCB_IMAGE_ORDER_MSB_FIRST;
878 return flip | (flip << 1);
883 bit_order(xcb_image_t *i)
885 uint32_t flip = i->byte_order != i->bit_order;
894 return flip | (flip << 1);
898 /* Convert from one byte order to another by flipping the
899 * low two bits of the byte index along a scanline
902 conversion_byte_swap(xcb_image_t *src, xcb_image_t *dst)
904 xcb_image_format_t ef = effective_format(src->format, src->bpp);
906 /* src_ef == dst_ef in all callers of this function */
907 if (ef == XCB_IMAGE_FORMAT_XY_PIXMAP) {
908 return bit_order(src) ^ bit_order(dst);
910 /* src_bpp == dst_bpp in all callers of this function */
911 return byte_order(src) ^ byte_order(dst);
916 xcb_image_convert (xcb_image_t * src,
919 xcb_image_format_t ef = effective_format(src->format, src->bpp);
921 /* Things will go horribly wrong here if a bad
922 image is passed in, so we check some things
923 up front just to be nice. */
924 assert(image_format_valid(src));
925 assert(image_format_valid(dst));
927 /* images must be the same size
928 * (yes, we could copy a sub-set)
930 if (src->width != dst->width ||
931 src->height != dst->height)
934 if (ef == effective_format(dst->format, dst->bpp) &&
935 src->bpp == dst->bpp)
937 if (src->unit == dst->unit &&
938 src->scanline_pad == dst->scanline_pad &&
939 src->byte_order == dst->byte_order &&
940 (ef == XCB_IMAGE_FORMAT_Z_PIXMAP ||
941 src->bit_order == dst->bit_order)) {
942 memcpy(dst->data, src->data, src->size);
946 uint32_t byteswap = conversion_byte_swap(src, dst);
947 uint32_t height = src->height;;
949 if (ef == XCB_IMAGE_FORMAT_Z_PIXMAP) {
950 if (src->bpp == 4 && src->byte_order != dst->byte_order)
953 if (src->bit_order != dst->bit_order)
955 height *= src->depth;
957 swap_image (src->data, src->stride, dst->data, dst->stride,
958 height, byteswap, bitswap, nibbleswap);
965 /* General case: Slow pixel copy. Should we optimize
966 Z24<->Z32 copies of either endianness? */
967 for (y = 0; y < src->height; y++) {
968 for (x = 0; x < src->width; x++) {
969 uint32_t pixel = xcb_image_get_pixel(src, x, y);
970 xcb_image_put_pixel(dst, x, y, pixel);
978 xcb_image_subimage(xcb_image_t * image,
988 xcb_image_t * result;
990 if (x + width > image->width)
992 if (y + height > image->height)
994 result = xcb_image_create(width, height, image->format,
995 image->scanline_pad, image->depth,
996 image->bpp, image->unit, image->byte_order,
1001 /* XXX FIXME For now, lose on performance. Sorry. */
1002 for (j = 0; j < height; j++) {
1003 for (i = 0; i < width; i++) {
1004 uint32_t pixel = xcb_image_get_pixel(image, x + i, y + j);
1005 xcb_image_put_pixel(result, i, j, pixel);