zbar-windows/test/test_images.c
2021-10-07 16:38:06 +08:00

533 lines
14 KiB
C

/*------------------------------------------------------------------------
* 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 "config.h"
#ifdef HAVE_INTTYPES_H
#include <inttypes.h>
#endif
#include <assert.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <zbar.h>
#include "test_images.h"
typedef enum format_type_e {
GRAY,
YUVP,
YVUP,
YUYV,
YVYU,
UYVY,
RGB888,
BGR888,
RGB565B = 0x0565,
RGB565L = 0x1565,
RGB555B = 0x0555,
RGB555L = 0x1555,
} format_type_t;
typedef struct format_def_s {
uint32_t format;
format_type_t type;
uint8_t bpp;
uint8_t xdiv, ydiv;
} format_def_t;
typedef union packed_u {
uint32_t u32[3];
uint16_t u16[6];
uint8_t u8[12];
} packed_t;
/* bar colors */
static const uint8_t Cr[] = { 0x22, 0x92, 0x80, 0xf0, 0x10, 0x80, 0x6e, 0xde };
static const uint8_t Cb[] = { 0x36, 0x10, 0x80, 0x5a, 0xa6, 0x80, 0xf0, 0xca };
static const format_def_t formats[] = {
{ fourcc('G', 'R', 'E', 'Y'), GRAY, 8, 0, 0 },
{ fourcc('Y', '8', '0', '0'), GRAY, 8, 0, 0 },
{ fourcc('Y', '8', ' ', ' '), GRAY, 8, 0, 0 },
{ fourcc('Y', '8', 0, 0), GRAY, 8, 0, 0 },
{ fourcc('Y', 'U', 'V', '9'), YUVP, 9, 4, 4 },
{ fourcc('Y', 'V', 'U', '9'), YVUP, 9, 4, 4 },
{ fourcc('I', '4', '2', '0'), YUVP, 12, 2, 2 },
{ fourcc('Y', 'U', '1', '2'), YUVP, 12, 2, 2 },
{ fourcc('Y', 'V', '1', '2'), YVUP, 12, 2, 2 },
{ fourcc('4', '1', '1', 'P'), YUVP, 12, 4, 1 },
{ fourcc('N', 'V', '1', '2'), YUVP, 12, 2, 2 },
{ fourcc('N', 'V', '2', '1'), YVUP, 12, 2, 2 },
{ fourcc('4', '2', '2', 'P'), YUVP, 16, 2, 1 },
{ fourcc('Y', 'U', 'Y', 'V'), YUYV, 16, 2, 1 },
{ fourcc('Y', 'U', 'Y', '2'), YUYV, 16, 2, 1 },
{ fourcc('Y', 'V', 'Y', 'U'), YVYU, 16, 2, 1 },
{ fourcc('U', 'Y', 'V', 'Y'), UYVY, 16, 2, 1 },
{
fourcc('R', 'G', 'B', '3'),
RGB888,
24,
},
{
fourcc('B', 'G', 'R', '3'),
BGR888,
24,
},
{
fourcc(3, 0, 0, 0),
RGB888,
32,
},
{
fourcc('R', 'G', 'B', '4'),
RGB888,
32,
},
{
fourcc('B', 'G', 'R', '4'),
BGR888,
32,
},
{
fourcc('R', 'G', 'B', 'P'),
RGB565L,
16,
},
{
fourcc('R', 'G', 'B', 'O'),
RGB555L,
16,
},
{
fourcc('R', 'G', 'B', 'R'),
RGB565B,
16,
},
{
fourcc('R', 'G', 'B', 'Q'),
RGB555B,
16,
},
{ 0 }
};
static const char *encoded_widths =
"9 111 212241113121211311141132 11111 311213121312121332111132 111 9";
const char *test_image_ean13_data = "6268964977804";
static int allocated_images = 0;
int test_image_check_cleanup()
{
if (allocated_images)
fprintf(stderr, "ERROR: %d image data buffers still allocated\n",
allocated_images);
/*else
fprintf(stderr, "all image data buffers freed\n");*/
return (allocated_images);
}
static void test_cleanup_handler(zbar_image_t *img)
{
void *data = (void *)zbar_image_get_data(img);
/*fprintf(stderr, "cleanup image data @%p\n", data);*/
free(data);
allocated_images--;
}
static inline const format_def_t *lookup_format(zbar_image_t *img)
{
uint32_t ifmt = zbar_image_get_format(img);
const format_def_t *fmt;
for (fmt = formats; fmt->format; fmt++)
if (fmt->format == ifmt)
break;
if (!fmt->format) {
fprintf(stderr, "ERROR: no %.4s (%08" PRIx32 ") format\n",
(char *)&ifmt, ifmt);
return (NULL);
}
return (fmt);
}
static inline const format_def_t *alloc_data(zbar_image_t *img)
{
allocated_images++;
const format_def_t *fmt = lookup_format(img);
if (!fmt)
return (NULL);
unsigned w = zbar_image_get_width(img);
unsigned h = zbar_image_get_height(img);
unsigned long planelen = w * h;
unsigned long datalen = planelen * fmt->bpp / 8;
uint8_t *data = malloc(datalen);
zbar_image_set_data(img, data, datalen, test_cleanup_handler);
/*fprintf(stderr, "create %.4s(%08"PRIx32") image data %lx bytes @%p\n",
(char*)&fmt->format, fmt->format, datalen, data);*/
return (fmt);
}
/* write intensity plane */
static inline uint8_t *fill_bars_y(uint8_t *p, unsigned w, unsigned h)
{
unsigned x, y, i;
unsigned y0 = (h + 31) / 30;
for (y = 0; y < y0; y++)
for (x = 0; x < w; x++)
*(p++) = 0xff;
for (; y < h - y0; y++)
for (x = 0, i = 0; x < w; i++) {
assert(i < 8);
unsigned x0 = (((i + 1) * w) + 7) >> 3;
assert(x0 <= w);
unsigned v = ((((i & 1) ? y : h - y) * 256) + h - 1) / h;
for (; x < x0; x++)
*(p++) = v;
}
for (; y < h; y++)
for (x = 0; x < w; x++)
*(p++) = 0xff;
return (p);
}
/* write Cb (U) or Cr (V) plane */
static inline uint8_t *fill_bars_uv(uint8_t *p, unsigned w, unsigned h,
const uint8_t *C)
{
unsigned x, y, i;
unsigned y0 = (h + 31) / 30;
for (y = 0; y < y0; y++)
for (x = 0; x < w; x++)
*(p++) = 0x80;
for (; y < h - y0; y++)
for (x = 0, i = 0; x < w; i++) {
assert(i < 8);
unsigned x0 = (((i + 1) * w) + 7) >> 3;
assert(x0 <= w);
for (; x < x0; x++)
*(p++) = C[i];
}
for (; y < h; y++)
for (x = 0; x < w; x++)
*(p++) = 0x80;
return (p);
}
/* write packed CbCr plane */
static inline uint8_t *fill_bars_nv(uint8_t *p, unsigned w, unsigned h,
format_type_t order)
{
unsigned x, y, i;
unsigned y0 = (h + 31) / 30;
for (y = 0; y < y0; y++)
for (x = 0; x < w; x++) {
*(p++) = 0x80;
*(p++) = 0x80;
}
for (; y < h - y0; y++)
for (x = 0, i = 0; x < w; i++) {
assert(i < 8);
unsigned x0 = (((i + 1) * w) + 7) >> 3;
assert(x0 <= w);
uint8_t u = (order == YUVP) ? Cb[i] : Cr[i];
uint8_t v = (order == YUVP) ? Cr[i] : Cb[i];
for (; x < x0; x++) {
*(p++) = u;
*(p++) = v;
}
}
for (; y < h; y++)
for (x = 0; x < w; x++) {
*(p++) = 0x80;
*(p++) = 0x80;
}
return (p);
}
/* write packed YCbCr plane */
static inline uint8_t *fill_bars_yuv(uint8_t *p, unsigned w, unsigned h,
format_type_t order)
{
unsigned x, y, i;
unsigned y0 = (h + 31) / 30;
packed_t yuv;
uint32_t *q = (uint32_t *)p;
w /= 2;
yuv.u8[0] = yuv.u8[2] = (order == UYVY) ? 0x80 : 0xff;
yuv.u8[1] = yuv.u8[3] = (order == UYVY) ? 0xff : 0x80;
for (y = 0; y < y0; y++)
for (x = 0; x < w; x++)
*(q++) = yuv.u32[0];
for (; y < h - y0; y++)
for (x = 0, i = 0; x < w; i++) {
assert(i < 8);
unsigned x0 = (((i + 1) * w) + 7) >> 3;
assert(x0 <= w);
unsigned v = ((((i & 1) ? y : h - y) * 256) + h - 1) / h;
if (order == UYVY) {
yuv.u8[0] = Cb[i];
yuv.u8[2] = Cr[i];
yuv.u8[1] = yuv.u8[3] = v;
} else {
yuv.u8[0] = yuv.u8[2] = v;
yuv.u8[1] = (order == YUYV) ? Cb[i] : Cr[i];
yuv.u8[3] = (order == YVYU) ? Cr[i] : Cb[i];
}
for (; x < x0; x++)
*(q++) = yuv.u32[0];
}
yuv.u8[0] = yuv.u8[2] = (order == UYVY) ? 0x80 : 0xff;
yuv.u8[1] = yuv.u8[3] = (order == UYVY) ? 0xff : 0x80;
for (; y < h; y++)
for (x = 0; x < w; x++)
*(q++) = yuv.u32[0];
return ((uint8_t *)q);
}
static inline uint8_t *fill_bars_rgb(uint8_t *p, unsigned w, unsigned h,
format_type_t order, int bpp)
{
unsigned x, y, i;
unsigned y0 = (h + 31) / 30;
packed_t rgb;
unsigned headlen = y0 * w * bpp / 8;
memset(p, 0xff, headlen);
uint32_t *q = (uint32_t *)(p + headlen);
for (y = y0; y < h - y0; y++)
for (x = 0, i = 0; x < w; i++) {
assert(i < 8);
/* FIXME clean this up... */
unsigned x0 = (((i + 1) * w) + 7) >> 3;
assert(x0 <= w);
unsigned yi = (i & 1) ? y : h - y;
unsigned v1, v0;
if (yi < h / 2 - 1) {
v1 = ((yi * 0x180) + h - 1) / h + 0x40;
v0 = 0x00;
} else {
v1 = 0xff;
v0 = (((yi - (h / 2)) * 0x180) + h - 1) / h + 0x40;
}
uint8_t r = (i & 4) ? v1 : v0;
uint8_t g = (i & 2) ? v1 : v0;
uint8_t b = (i & 1) ? v1 : v0;
if (bpp == 32) {
if (order == RGB888) {
rgb.u8[0] = 0xff;
rgb.u8[1] = r;
rgb.u8[2] = g;
rgb.u8[3] = b;
} else {
rgb.u8[0] = b;
rgb.u8[1] = g;
rgb.u8[2] = r;
rgb.u8[3] = 0xff;
}
for (; x < x0; x++)
*(q++) = rgb.u32[0];
} else if (bpp == 24) {
rgb.u8[0] = rgb.u8[3] = rgb.u8[6] = rgb.u8[9] =
(order == RGB888) ? r : b;
rgb.u8[1] = rgb.u8[4] = rgb.u8[7] = rgb.u8[10] = g;
rgb.u8[2] = rgb.u8[5] = rgb.u8[8] = rgb.u8[11] =
(order == RGB888) ? b : r;
for (; x < x0; x += 4) {
*(q++) = rgb.u32[0];
*(q++) = rgb.u32[1];
*(q++) = rgb.u32[2];
}
} else {
assert(bpp == 16);
r = ((r + 7) / 8) & 0x1f;
b = ((b + 7) / 8) & 0x1f;
if ((order & 0x0fff) == 0x0555) {
g = ((g + 7) / 8) & 0x1f;
rgb.u16[0] = b | (g << 5) | (r << 10);
} else {
g = ((g + 3) / 4) & 0x3f;
rgb.u16[0] = b | (g << 5) | (r << 11);
}
if (order & 0x1000)
rgb.u16[0] = (rgb.u16[0] >> 8) | (rgb.u16[0] << 8);
rgb.u16[1] = rgb.u16[0];
for (; x < x0; x += 2)
*(q++) = rgb.u32[0];
}
}
memset(q, 0xff, headlen);
return (((uint8_t *)q) + headlen);
}
int test_image_bars(zbar_image_t *img)
{
const format_def_t *fmt = alloc_data(img);
if (!fmt)
return (-1);
unsigned w = zbar_image_get_width(img);
unsigned h = zbar_image_get_height(img);
uint8_t *data = (void *)zbar_image_get_data(img);
assert(data);
uint8_t *p = data;
switch (fmt->type) {
case GRAY:
case YUVP: /* planar YUV */
case YVUP:
p = fill_bars_y(p, w, h);
if (fmt->type != GRAY) {
w = (w + fmt->xdiv - 1) / fmt->xdiv;
h = (h + fmt->ydiv - 1) / fmt->ydiv;
} else
break;
if (fmt->format == fourcc('N', 'V', '1', '2') ||
fmt->format == fourcc('N', 'V', '2', '1'))
p = fill_bars_nv(p, w, h, fmt->type);
else if (fmt->type == YUVP || fmt->type == YVUP) {
p = fill_bars_uv(p, w, h, (fmt->type == YUVP) ? Cb : Cr);
p = fill_bars_uv(p, w, h, (fmt->type == YUVP) ? Cr : Cb);
}
break;
case YUYV: /* packed YUV */
case YVYU:
case UYVY:
p = fill_bars_yuv(p, w, h, fmt->type);
break;
default: /* RGB */
p = fill_bars_rgb(p, w, h, fmt->type, fmt->bpp);
break;
}
assert(p == data + zbar_image_get_data_length(img));
return (0);
}
int test_image_ean13(zbar_image_t *img)
{
unsigned w = 114, h = 85;
zbar_image_set_size(img, w, h);
const format_def_t *fmt = alloc_data(img);
if (!fmt)
return (-1);
uint8_t *data = (void *)zbar_image_get_data(img);
unsigned int datalen = zbar_image_get_data_length(img);
assert(data && datalen);
uint8_t *p = data;
/* FIXME randomize? */
memset(data, 0x80, datalen);
int nrep = 1, nskip = 0;
switch (fmt->type) {
case YUVP: /* planar YUV */
case YVUP:
case GRAY:
break;
case UYVY: /* packed YUV */
p++;
case YUYV:
case YVYU:
nskip = 1;
break;
default: /* RGB */
nrep = fmt->bpp / 8;
}
int y = 0, x, i;
for (; y < 10 && y < h; y++)
for (x = 0; x < w; x++) {
for (i = 0; i < nrep; i++)
*p++ = 0xff;
p += nskip;
}
for (; y < h - 10; y++) {
uint8_t color = 0xff;
const char *c;
for (x = 0, c = encoded_widths; *c; c++) {
int dx;
if (*c == ' ')
continue;
for (dx = *c - '0'; dx > 0; dx--) {
for (i = 0; i < nrep; i++)
*p++ = color;
p += nskip;
x++;
}
color = ~color;
}
assert(!color);
for (; x < w; x++) {
for (i = 0; i < nrep; i++)
*p++ = 0xff;
p += nskip;
}
assert(x == w);
}
for (; y < h; y++)
for (x = 0; x < w; x++) {
for (i = 0; i < nrep; i++)
*p++ = 0xff;
p += nskip;
}
if (fmt->type == UYVY)
p--;
assert(p == data + datalen);
return (0);
}