Skip to content

Add qrio.QRDecoder.find() to locate codes without decoding #8467

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Oct 25, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
51 changes: 41 additions & 10 deletions shared-bindings/qrio/QRDecoder.c
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,19 @@ STATIC mp_obj_t qrio_qrdecoder_make_new(const mp_obj_type_t *type, size_t n_args
return self;
}


STATIC void verify_buffer_size(qrio_qrdecoder_obj_t *self, mp_obj_t *buffer, size_t len, qrio_pixel_policy_t policy) {
int width = shared_module_qrio_qrdecoder_get_width(self);
int height = shared_module_qrio_qrdecoder_get_height(self);

// verify that the buffer is big enough
int sz = width * height;
if (policy != QRIO_EVERY_BYTE) {
sz *= 2;
}
mp_get_index(mp_obj_get_type(*buffer), len, MP_OBJ_NEW_SMALL_INT(sz - 1), false);
}

//| def decode(
//| self, buffer: ReadableBuffer, pixel_policy: PixelPolicy = PixelPolicy.EVERY_BYTE
//| ) -> List[QRInfo]:
Expand All @@ -73,22 +86,39 @@ STATIC mp_obj_t qrio_qrdecoder_decode(size_t n_args, const mp_obj_t *pos_args, m

mp_buffer_info_t bufinfo;
mp_get_buffer_raise(args[ARG_buffer].u_obj, &bufinfo, MP_BUFFER_READ);

int width = shared_module_qrio_qrdecoder_get_width(self);
int height = shared_module_qrio_qrdecoder_get_height(self);

// verify that the buffer is big enough
int sz = width * height;
qrio_pixel_policy_t policy = cp_enum_value(&qrio_pixel_policy_type, args[ARG_pixel_policy].u_obj, MP_QSTR_pixel_policy);
if (policy != QRIO_EVERY_BYTE) {
sz *= 2;
}
mp_get_index(mp_obj_get_type(args[ARG_buffer].u_obj), bufinfo.len, MP_OBJ_NEW_SMALL_INT(sz - 1), false);
verify_buffer_size(self, &args[ARG_buffer].u_obj, bufinfo.len, policy);

return shared_module_qrio_qrdecoder_decode(self, &bufinfo, policy);
}
MP_DEFINE_CONST_FUN_OBJ_KW(qrio_qrdecoder_decode_obj, 1, qrio_qrdecoder_decode);


//| def find(
//| self, buffer: ReadableBuffer, pixel_policy: PixelPolicy = PixelPolicy.EVERY_BYTE
//| ) -> List[QRPosition]:
//| """Find all visible QR codes from the given image. The size of the buffer must be at least ``length``×``width`` bytes for `EVERY_BYTE`, and 2×``length``×``width`` bytes for `EVEN_BYTES` or `ODD_BYTES`."""
STATIC mp_obj_t qrio_qrdecoder_find(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
qrio_qrdecoder_obj_t *self = MP_OBJ_TO_PTR(pos_args[0]);

enum { ARG_buffer, ARG_pixel_policy };
static const mp_arg_t allowed_args[] = {
{ MP_QSTR_buffer, MP_ARG_OBJ | MP_ARG_REQUIRED, {.u_int = 0} },
{ MP_QSTR_pixel_policy, MP_ARG_OBJ, {.u_obj = MP_ROM_PTR((mp_obj_t *)&qrio_pixel_policy_EVERY_BYTE_obj)} },
};
mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)];
mp_arg_parse_all(n_args - 1, pos_args + 1, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args);

mp_buffer_info_t bufinfo;
mp_get_buffer_raise(args[ARG_buffer].u_obj, &bufinfo, MP_BUFFER_READ);
qrio_pixel_policy_t policy = cp_enum_value(&qrio_pixel_policy_type, args[ARG_pixel_policy].u_obj, MP_QSTR_pixel_policy);
verify_buffer_size(self, &args[ARG_buffer].u_obj, bufinfo.len, policy);

return shared_module_qrio_qrdecoder_find(self, &bufinfo, policy);
}
MP_DEFINE_CONST_FUN_OBJ_KW(qrio_qrdecoder_find_obj, 1, qrio_qrdecoder_find);


//| width: int
//| """The width of image the decoder expects"""
STATIC mp_obj_t qrio_qrdecoder_get_width(mp_obj_t self_in) {
Expand Down Expand Up @@ -135,6 +165,7 @@ STATIC const mp_rom_map_elem_t qrio_qrdecoder_locals_table[] = {
{ MP_ROM_QSTR(MP_QSTR_width), MP_ROM_PTR(&qrio_qrdecoder_width_obj) },
{ MP_ROM_QSTR(MP_QSTR_height), MP_ROM_PTR(&qrio_qrdecoder_height_obj) },
{ MP_ROM_QSTR(MP_QSTR_decode), MP_ROM_PTR(&qrio_qrdecoder_decode_obj) },
{ MP_ROM_QSTR(MP_QSTR_find), MP_ROM_PTR(&qrio_qrdecoder_find_obj) },
};

STATIC MP_DEFINE_CONST_DICT(qrio_qrdecoder_locals, qrio_qrdecoder_locals_table);
Expand Down
63 changes: 63 additions & 0 deletions shared-bindings/qrio/QRInfo.c
Original file line number Diff line number Diff line change
Expand Up @@ -63,3 +63,66 @@ const mp_obj_namedtuple_type_t qrio_qrinfo_type_obj = {
MP_QSTR_data_type,
},
};

//| class QRPosition:
//| """Information about a non-decoded QR code"""
//|
//| top_left_x: int
//| """X coordinate of the top left corner"""
//|
//| top_left_y: int
//| """Y coordinate of the top left corner"""
//|
//| top_right_x: int
//| """X coordinate of the top right corner"""
//|
//| top_right_y: int
//| """Y coordinate of the top right corner"""
//|
//| bottom_right_x: int
//| """X coordinate of the bottom right corner"""
//|
//| bottom_right_y: int
//| """Y coordinate of the bottom right corner"""
//|
//| bottom_left_x: int
//| """X coordinate of the bottom left corner"""
//|
//| bottom_left_y: int
//| """Y coordinate of the bottom left corner"""
//|
//| size: int
//| """The number of bits the code contains"""
//|

const mp_obj_namedtuple_type_t qrio_qrposition_type_obj = {
.base = {
.base = {
.type = &mp_type_type
},
.flags = MP_TYPE_FLAG_EXTENDED,
.name = MP_QSTR_QRPosition,
.print = namedtuple_print,
.parent = &mp_type_tuple,
.make_new = namedtuple_make_new,
.attr = namedtuple_attr,
MP_TYPE_EXTENDED_FIELDS(
.unary_op = mp_obj_tuple_unary_op,
.binary_op = mp_obj_tuple_binary_op,
.subscr = mp_obj_tuple_subscr,
.getiter = mp_obj_tuple_getiter,
),
},
.n_fields = 9,
.fields = {
MP_QSTR_top_left_x,
MP_QSTR_top_left_y,
MP_QSTR_top_right_x,
MP_QSTR_top_right_y,
MP_QSTR_bottom_right_x,
MP_QSTR_bottom_right_y,
MP_QSTR_bottom_left_x,
MP_QSTR_bottom_left_y,
MP_QSTR_size,
},
};
1 change: 1 addition & 0 deletions shared-bindings/qrio/QRInfo.h
Original file line number Diff line number Diff line change
Expand Up @@ -29,3 +29,4 @@
#include "py/objnamedtuple.h"

extern const mp_obj_namedtuple_type_t qrio_qrinfo_type_obj;
extern const mp_obj_namedtuple_type_t qrio_qrposition_type_obj;
40 changes: 35 additions & 5 deletions shared-module/qrio/QRDecoder.c
Original file line number Diff line number Diff line change
Expand Up @@ -98,21 +98,21 @@ STATIC mp_obj_t data_type(int type) {
return mp_obj_new_int(type);
}

mp_obj_t shared_module_qrio_qrdecoder_decode(qrdecoder_qrdecoder_obj_t *self, const mp_buffer_info_t *bufinfo, qrio_pixel_policy_t policy) {
STATIC void quirc_fill_buffer(qrdecoder_qrdecoder_obj_t *self, void *buf, qrio_pixel_policy_t policy) {
int width, height;
uint8_t *framebuffer = quirc_begin(self->quirc, &width, &height);
uint8_t *src = bufinfo->buf;
uint8_t *src = buf;

switch (policy) {
case QRIO_RGB565: {
uint16_t *src16 = bufinfo->buf;
uint16_t *src16 = buf;
for (int i = 0; i < width * height; i++) {
framebuffer[i] = (src16[i] >> 3) & 0xfc;
}
break;
}
case QRIO_RGB565_SWAPPED: {
uint16_t *src16 = bufinfo->buf;
uint16_t *src16 = buf;
for (int i = 0; i < width * height; i++) {
framebuffer[i] = (__builtin_bswap16(src16[i]) >> 3) & 0xfc;
}
Expand All @@ -133,19 +133,49 @@ mp_obj_t shared_module_qrio_qrdecoder_decode(qrdecoder_qrdecoder_obj_t *self, co
break;
}
quirc_end(self->quirc);
}


mp_obj_t shared_module_qrio_qrdecoder_decode(qrdecoder_qrdecoder_obj_t *self, const mp_buffer_info_t *bufinfo, qrio_pixel_policy_t policy) {
quirc_fill_buffer(self, bufinfo->buf, policy);
int count = quirc_count(self->quirc);
mp_obj_t result = mp_obj_new_list(0, NULL);
for (int i = 0; i < count; i++) {
quirc_extract(self->quirc, i, &self->code);
mp_obj_t code_obj;
if (quirc_decode(&self->code, &self->data) != QUIRC_SUCCESS) {
continue;
}
mp_obj_t elems[2] = {
mp_obj_new_bytes(self->data.payload, self->data.payload_len),
data_type(self->data.data_type),
};
mp_obj_t code_obj = namedtuple_make_new((const mp_obj_type_t *)&qrio_qrinfo_type_obj, 2, 0, elems);
code_obj = namedtuple_make_new((const mp_obj_type_t *)&qrio_qrinfo_type_obj, 2, 0, elems);
mp_obj_list_append(result, code_obj);
}
return result;
}


mp_obj_t shared_module_qrio_qrdecoder_find(qrdecoder_qrdecoder_obj_t *self, const mp_buffer_info_t *bufinfo, qrio_pixel_policy_t policy) {
quirc_fill_buffer(self, bufinfo->buf, policy);
int count = quirc_count(self->quirc);
mp_obj_t result = mp_obj_new_list(0, NULL);
for (int i = 0; i < count; i++) {
quirc_extract(self->quirc, i, &self->code);
mp_obj_t code_obj;
mp_obj_t elems[9] = {
mp_obj_new_int(self->code.corners[0].x),
mp_obj_new_int(self->code.corners[0].y),
mp_obj_new_int(self->code.corners[1].x),
mp_obj_new_int(self->code.corners[1].y),
mp_obj_new_int(self->code.corners[2].x),
mp_obj_new_int(self->code.corners[2].y),
mp_obj_new_int(self->code.corners[3].x),
mp_obj_new_int(self->code.corners[3].y),
mp_obj_new_int(self->code.size),
};
code_obj = namedtuple_make_new((const mp_obj_type_t *)&qrio_qrposition_type_obj, 9, 0, elems);
mp_obj_list_append(result, code_obj);
}
return result;
Expand Down
1 change: 1 addition & 0 deletions shared-module/qrio/QRDecoder.h
Original file line number Diff line number Diff line change
Expand Up @@ -43,3 +43,4 @@ int shared_module_qrio_qrdecoder_get_width(qrdecoder_qrdecoder_obj_t *);
void shared_module_qrio_qrdecoder_set_height(qrdecoder_qrdecoder_obj_t *, int height);
void shared_module_qrio_qrdecoder_set_width(qrdecoder_qrdecoder_obj_t *, int width);
mp_obj_t shared_module_qrio_qrdecoder_decode(qrdecoder_qrdecoder_obj_t *, const mp_buffer_info_t *bufinfo, qrio_pixel_policy_t policy);
mp_obj_t shared_module_qrio_qrdecoder_find(qrdecoder_qrdecoder_obj_t *, const mp_buffer_info_t *bufinfo, qrio_pixel_policy_t policy);