diff options
Diffstat (limited to 'zbar/window/ximage.c')
-rw-r--r-- | zbar/window/ximage.c | 201 |
1 files changed, 201 insertions, 0 deletions
diff --git a/zbar/window/ximage.c b/zbar/window/ximage.c new file mode 100644 index 0000000..17ee7e4 --- /dev/null +++ b/zbar/window/ximage.c @@ -0,0 +1,201 @@ +/*------------------------------------------------------------------------ + * Copyright 2007-2009 (c) Jeff Brown <spadix@users.sourceforge.net> + * + * This file is part of the ZBar Bar Code Reader. + * + * The ZBar Bar Code Reader is free software; you can redistribute it + * and/or modify it under the terms of the GNU Lesser Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * The ZBar Bar Code Reader is distributed in the hope that it will be + * useful, but WITHOUT ANY WARRANTY; without even the implied warranty + * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser Public License for more details. + * + * You should have received a copy of the GNU Lesser Public License + * along with the ZBar Bar Code Reader; if not, write to the Free + * Software Foundation, Inc., 51 Franklin St, Fifth Floor, + * Boston, MA 02110-1301 USA + * + * http://sourceforge.net/projects/zbar + *------------------------------------------------------------------------*/ + +#include "image.h" +#include "window.h" +#include "x.h" + +static int ximage_cleanup(zbar_window_t *w) +{ + window_state_t *x = w->state; + if (x->img.x) + free(x->img.x); + x->img.x = NULL; + return (0); +} + +static inline int ximage_init(zbar_window_t *w, zbar_image_t *img, + int format_change) +{ + ximage_cleanup(w); + XImage *ximg = w->state->img.x = calloc(1, sizeof(XImage)); + ximg->width = img->width; + ximg->height = img->height; + ximg->format = ZPixmap; + ximg->byte_order = LSBFirst; + ximg->bitmap_unit = 8; + ximg->bitmap_bit_order = MSBFirst; + ximg->bitmap_pad = 8; + + const zbar_format_def_t *fmt = _zbar_format_lookup(w->format); + if (fmt->group == ZBAR_FMT_RGB_PACKED) { + ximg->depth = ximg->bits_per_pixel = fmt->p.rgb.bpp << 3; + ximg->red_mask = (0xff >> RGB_SIZE(fmt->p.rgb.red)) + << RGB_OFFSET(fmt->p.rgb.red); + ximg->green_mask = (0xff >> RGB_SIZE(fmt->p.rgb.green)) + << RGB_OFFSET(fmt->p.rgb.green); + ximg->blue_mask = (0xff >> RGB_SIZE(fmt->p.rgb.blue)) + << RGB_OFFSET(fmt->p.rgb.blue); + } else { + ximg->depth = ximg->bits_per_pixel = 8; + ximg->red_mask = ximg->green_mask = ximg->blue_mask = 0xff; + } + + if (!XInitImage(ximg)) + return (err_capture_int(w, SEV_ERROR, ZBAR_ERR_XPROTO, __func__, + "unable to init XImage for format %x", + w->format)); + + w->dst_width = img->width; + w->dst_height = img->height; + + /* FIXME implement some basic scaling */ + w->scale_num = w->scale_den = 1; + + zprintf(3, + "new XImage %.4s(%08" PRIx32 ") %dx%d" + " from %.4s(%08" PRIx32 ") %dx%d\n", + (char *)&w->format, w->format, ximg->width, ximg->height, + (char *)&img->format, img->format, img->width, img->height); + zprintf(4, " masks: %08lx %08lx %08lx\n", ximg->red_mask, + ximg->green_mask, ximg->blue_mask); + return (0); +} + +static int ximage_draw(zbar_window_t *w, zbar_image_t *img) +{ + window_state_t *x = w->state; + XImage *ximg = x->img.x; + assert(ximg); + ximg->data = (void *)img->data; + + point_t src = { 0, 0 }; + point_t dst = w->scaled_offset; + if (dst.x < 0) { + src.x = -dst.x; + dst.x = 0; + } + if (dst.y < 0) { + src.y = -dst.y; + dst.y = 0; + } + point_t size = w->scaled_size; + if (size.x > w->width) + size.x = w->width; + if (size.y > w->height) + size.y = w->height; + + XPutImage(w->display, w->xwin, x->gc, ximg, src.x, src.y, dst.x, dst.y, + size.x, size.y); + ximg->data = NULL; + return (0); +} + +static uint32_t ximage_formats[4][5] = { + { /* 8bpp */ + /* FIXME fourcc('Y','8','0','0'), */ + fourcc('R', 'G', 'B', '1'), fourcc('B', 'G', 'R', '1'), 0 }, + { /* 16bpp */ + fourcc('R', 'G', 'B', 'P'), fourcc('R', 'G', 'B', 'O'), + fourcc('R', 'G', 'B', 'R'), fourcc('R', 'G', 'B', 'Q'), 0 }, + { /* 24bpp */ + fourcc('R', 'G', 'B', '3'), fourcc('B', 'G', 'R', '3'), 0 }, + { /* 32bpp */ + fourcc('R', 'G', 'B', '4'), fourcc('B', 'G', 'R', '4'), 0 }, +}; + +static int ximage_probe_format(zbar_window_t *w, uint32_t format) +{ + const zbar_format_def_t *fmt = _zbar_format_lookup(format); + + XVisualInfo visreq, *visuals = NULL; + memset(&visreq, 0, sizeof(XVisualInfo)); + + visreq.depth = fmt->p.rgb.bpp << 3; + visreq.red_mask = (0xff >> RGB_SIZE(fmt->p.rgb.red)) + << RGB_OFFSET(fmt->p.rgb.red); + visreq.green_mask = (0xff >> RGB_SIZE(fmt->p.rgb.green)) + << RGB_OFFSET(fmt->p.rgb.green); + visreq.blue_mask = (0xff >> RGB_SIZE(fmt->p.rgb.blue)) + << RGB_OFFSET(fmt->p.rgb.blue); + + int n; + visuals = XGetVisualInfo(w->display, + VisualDepthMask | VisualRedMaskMask | + VisualGreenMaskMask | VisualBlueMaskMask, + &visreq, &n); + + zprintf(8, "bits=%d r=%08lx g=%08lx b=%08lx: n=%d visuals=%p\n", + visreq.depth, visreq.red_mask, visreq.green_mask, visreq.blue_mask, + n, visuals); + if (!visuals) + return (1); + XFree(visuals); + if (!n) + return (-1); + + return (0); +} + +int _zbar_window_probe_ximage(zbar_window_t *w) +{ + /* FIXME determine supported formats/depths */ + int n; + XPixmapFormatValues *formats = XListPixmapFormats(w->display, &n); + if (!formats) + return (err_capture(w, SEV_ERROR, ZBAR_ERR_XPROTO, __func__, + "unable to query XImage formats")); + + int i; + for (i = 0; i < n; i++) { + if (formats[i].depth & 0x7 || formats[i].depth > 0x20) { + zprintf(2, " [%d] depth=%d bpp=%d: not supported\n", i, + formats[i].depth, formats[i].bits_per_pixel); + continue; + } + int fmtidx = formats[i].depth / 8 - 1; + int j, n = 0; + for (j = 0; ximage_formats[fmtidx][j]; j++) + if (!ximage_probe_format(w, ximage_formats[fmtidx][j])) { + zprintf(2, " [%d] depth=%d bpp=%d: %.4s(%08" PRIx32 ")\n", i, + formats[i].depth, formats[i].bits_per_pixel, + (char *)&ximage_formats[fmtidx][j], + ximage_formats[fmtidx][j]); + _zbar_window_add_format(w, ximage_formats[fmtidx][j]); + n++; + } + if (!n) + zprintf(2, " [%d] depth=%d bpp=%d: no visuals\n", i, + formats[i].depth, formats[i].bits_per_pixel); + } + XFree(formats); + + if (!w->formats || !w->formats[0]) + return (err_capture(w, SEV_ERROR, ZBAR_ERR_UNSUPPORTED, __func__, + "no usable XImage formats found")); + + w->init = ximage_init; + w->draw_image = ximage_draw; + w->cleanup = ximage_cleanup; + return (0); +} |