From e06babd05b3cebf0c1512146f1573912f5c13e28 Mon Sep 17 00:00:00 2001 From: Radomir Dopieralski Date: Sun, 8 Oct 2023 23:08:08 +0200 Subject: [PATCH] Add qrio.QRDecoder.find() to locate codes without decoding Fix #8452 --- shared-bindings/qrio/QRDecoder.c | 51 +++++++++++++++++++++++++------- shared-bindings/qrio/QRInfo.c | 36 ++++++++++++++++++++++ shared-bindings/qrio/QRInfo.h | 1 + shared-module/qrio/QRDecoder.c | 32 +++++++++++++++----- shared-module/qrio/QRDecoder.h | 2 +- 5 files changed, 103 insertions(+), 19 deletions(-) diff --git a/shared-bindings/qrio/QRDecoder.c b/shared-bindings/qrio/QRDecoder.c index e8cabade33456..3bd7c95c34f52 100644 --- a/shared-bindings/qrio/QRDecoder.c +++ b/shared-bindings/qrio/QRDecoder.c @@ -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]: @@ -73,21 +86,38 @@ 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); + 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); - int width = shared_module_qrio_qrdecoder_get_width(self); - int height = shared_module_qrio_qrdecoder_get_height(self); + return shared_module_qrio_qrdecoder_decode(self, &bufinfo, policy, true); +} +MP_DEFINE_CONST_FUN_OBJ_KW(qrio_qrdecoder_decode_obj, 1, qrio_qrdecoder_decode); - // verify that the buffer is big enough - int sz = width * height; + +//| 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); - 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); + return shared_module_qrio_qrdecoder_decode(self, &bufinfo, policy, false); } -MP_DEFINE_CONST_FUN_OBJ_KW(qrio_qrdecoder_decode_obj, 1, qrio_qrdecoder_decode); +MP_DEFINE_CONST_FUN_OBJ_KW(qrio_qrdecoder_find_obj, 1, qrio_qrdecoder_find); + //| width: int //| """The width of image the decoder expects""" @@ -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); diff --git a/shared-bindings/qrio/QRInfo.c b/shared-bindings/qrio/QRInfo.c index d53e638f81d45..1a191f1c424ce 100644 --- a/shared-bindings/qrio/QRInfo.c +++ b/shared-bindings/qrio/QRInfo.c @@ -63,3 +63,39 @@ const mp_obj_namedtuple_type_t qrio_qrinfo_type_obj = { MP_QSTR_data_type, }, }; + +//| class QRPosition: +//| """Information about a non-decoded QR code""" +//| + +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, + }, +}; diff --git a/shared-bindings/qrio/QRInfo.h b/shared-bindings/qrio/QRInfo.h index 956cb427357c4..6c587433790f3 100644 --- a/shared-bindings/qrio/QRInfo.h +++ b/shared-bindings/qrio/QRInfo.h @@ -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; diff --git a/shared-module/qrio/QRDecoder.c b/shared-module/qrio/QRDecoder.c index f7b25362e4738..5237396f34dff 100644 --- a/shared-module/qrio/QRDecoder.c +++ b/shared-module/qrio/QRDecoder.c @@ -98,7 +98,7 @@ 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) { +mp_obj_t shared_module_qrio_qrdecoder_decode(qrdecoder_qrdecoder_obj_t *self, const mp_buffer_info_t *bufinfo, qrio_pixel_policy_t policy, bool decode) { int width, height; uint8_t *framebuffer = quirc_begin(self->quirc, &width, &height); uint8_t *src = bufinfo->buf; @@ -138,14 +138,30 @@ mp_obj_t shared_module_qrio_qrdecoder_decode(qrdecoder_qrdecoder_obj_t *self, co mp_obj_t result = mp_obj_new_list(0, NULL); for (int i = 0; i < count; i++) { quirc_extract(self->quirc, i, &self->code); - if (quirc_decode(&self->code, &self->data) != QUIRC_SUCCESS) { - continue; + mp_obj_t code_obj; + if (decode) { + 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), + }; + code_obj = namedtuple_make_new((const mp_obj_type_t *)&qrio_qrinfo_type_obj, 2, 0, elems); + } else { + 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_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); mp_obj_list_append(result, code_obj); } return result; diff --git a/shared-module/qrio/QRDecoder.h b/shared-module/qrio/QRDecoder.h index 096dcd2e3f4fc..b6d836456bfe1 100644 --- a/shared-module/qrio/QRDecoder.h +++ b/shared-module/qrio/QRDecoder.h @@ -42,4 +42,4 @@ int shared_module_qrio_qrdecoder_get_height(qrdecoder_qrdecoder_obj_t *); 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_decode(qrdecoder_qrdecoder_obj_t *, const mp_buffer_info_t *bufinfo, qrio_pixel_policy_t policy, bool decode);