Draw finder, data using opencv instead zint
authorKwanghoon Son <k.son@samsung.com>
Thu, 18 Jul 2024 06:06:19 +0000 (15:06 +0900)
committerKwanghoon Son <k.son@samsung.com>
Fri, 26 Jul 2024 03:49:18 +0000 (12:49 +0900)
Change-Id: I516db8cf79a0ca8c554cb97ef78af5742b8bd2cd
Signed-off-by: Kwanghoon Son <k.son@samsung.com>
mv_barcode/barcode_generator/src/BarcodeGenerator.cpp

index 8a6868a9115250720a5a0222aef1adaf1b8a9824..0512ad42d784d6c4c78d7142489b0d7bd1226825 100644 (file)
@@ -246,25 +246,6 @@ static int createBarcode(zint_symbol *symbol, const BarcodeConfig &config)
        symbol->border_width = 1;
        symbol->height = 50;
 
-       switch (config.data_shape) {
-       case MV_BARCODE_GENERATE_ATTR_SHAPE_CIRCLE:
-               symbol->output_options |= BARCODE_DATA_CIRCLE;
-               break;
-       default:
-               break;
-       }
-
-       switch (config.finder_shape) {
-       case MV_BARCODE_GENERATE_ATTR_SHAPE_ROUND_RECT:
-               symbol->output_options |= BARCODE_FINDER_ROUNDRECT;
-               break;
-       case MV_BARCODE_GENERATE_ATTR_SHAPE_CIRCLE:
-               symbol->output_options |= BARCODE_FINDER_CIRCLE;
-               break;
-       default:
-               break;
-       }
-
        if (type == ZINT_BARCODE_QR) {
                symbol->whitespace_width = 0;
        } else {
@@ -547,32 +528,119 @@ static void changeColor(cv::Mat &buf, const BarcodeConfig &config)
        changeTargetColor(buf, cv::Scalar(255, 255, 255), convert_to_scalar(config.bgcolor));
 }
 
-int symbol_to_source(zint_symbol *symbol, const BarcodeConfig &config, mv_source_h source)
+static inline bool is_finder(int x, int y, int w, int h)
+{
+       return ((x < 16 && y < 16) || (x < 16 && h - y <= 16) || (w - x <= 16 && y < 16));
+}
+
+/*
+ * Draw finder pattern
+ * First loop is for position top-left, top-right, bottom-left.
+ * Second loop is color and size for pattern
+ */
+static void drawFinderPattern(cv::Mat &resize_buf, int resize_scale, int org_height, int org_width,
+                                                         mv_barcode_generate_attr_shape_e shape)
+{
+       int posx[3] = { 2, org_width - 16, 2 };
+       int posy[3] = { 2, 2, org_height - 16 };
+       for (int pos = 0; pos < 3; pos++) {
+               for (int sz = 3; sz > 0; sz--) {
+                       int x = posx[pos] + 2 * (3 - sz);
+                       int y = posy[pos] + 2 * (3 - sz);
+                       int finder_lenght = (sz * 2 + 1) * 2;
+                       auto rect = cv::Rect(x * resize_scale, y * resize_scale, resize_scale * finder_lenght,
+                                                                resize_scale * finder_lenght);
+                       auto color = cv::Scalar(sz % 2 == 0 ? 255 : 0);
+                       switch (shape) {
+                       case MV_BARCODE_GENERATE_ATTR_SHAPE_RECT:
+                               cv::rectangle(resize_buf, rect, color, -1);
+                               break;
+                       case MV_BARCODE_GENERATE_ATTR_SHAPE_ROUND_RECT:
+                               __round_rect(resize_buf, rect, color);
+                               break;
+                       case MV_BARCODE_GENERATE_ATTR_SHAPE_CIRCLE:
+                               cv::circle(resize_buf,
+                                                  cv::Point((x + 2 * sz) * resize_scale + resize_scale / 2,
+                                                                        (y + 2 * sz) * resize_scale + resize_scale / 2),
+                                                  finder_lenght / 2 * resize_scale, color, -1);
+                               break;
+
+                       default:
+                               break;
+                       }
+               }
+       }
+}
+
+/*
+ * Draw data pattern
+ * buf already resize x2(by libzint), so finder size is not 7x7, but 14x14.
+ * Loop also jump 2 pixel each.
+ */
+static void drawDataPattern(cv::Mat &resize_buf, const cv::Mat &buf, int resize_scale, int org_height, int org_width,
+                                                       mv_barcode_generate_attr_shape_e shape)
 {
-       int ret = mv_barcode_generate_symbol(symbol, config);
-       if (ret != MEDIA_VISION_ERROR_NONE) {
-               LOGE("mv_barcode_generate_symbol failed error : %d", ret);
-               return ret;
+       for (int y = 2; y < org_height - 2; y += 2) {
+               for (int x = 2; x < org_width - 2; x += 2) {
+                       if (is_finder(x, y, org_width, org_height) || buf.at<unsigned char>(y, x, 0) == 255)
+                               continue;
+                       if (shape == MV_BARCODE_GENERATE_ATTR_SHAPE_RECT)
+                               cv::rectangle(resize_buf,
+                                                         cv::Rect(x * resize_scale, y * resize_scale, resize_scale * 2, resize_scale * 2),
+                                                         cv::Scalar(0), -1);
+                       else
+                               /* if radius is same as resize_scale, data look so dense, so -4 */
+                               cv::circle(resize_buf,
+                                                  cv::Point(x * resize_scale + resize_scale / 2, y * resize_scale + resize_scale / 2),
+                                                  resize_scale - 4, cv::Scalar(0), -1);
+               }
        }
+}
+static void drawDesignQR(cv::Mat &buf, const BarcodeConfig &config)
+{
+       if (config.type != MV_BARCODE_QR || (config.data_shape == MV_BARCODE_GENERATE_ATTR_SHAPE_RECT &&
+                                                                                config.finder_shape == MV_BARCODE_GENERATE_ATTR_SHAPE_RECT))
+               return;
+       const int resize_scale = 16;
+       cv::Mat resize_buf(buf.rows * resize_scale, buf.cols * resize_scale, CV_8UC1, cv::Scalar(255));
+
+       drawFinderPattern(resize_buf, resize_scale, buf.rows, buf.cols, config.finder_shape);
+       drawDataPattern(resize_buf, buf, resize_scale, buf.rows, buf.cols, config.data_shape);
+
+       cv::cvtColor(resize_buf, buf, cv::COLOR_GRAY2BGR);
+}
+
+static int symbol_to_buf(zint_symbol *symbol, const BarcodeConfig &config, cv::Mat &buf)
+{
+       MEDIA_VISION_CHECK_ERR(mv_barcode_generate_symbol(symbol, config), "mv_barcode_generate_symbol failed");
 
        // This not copy data, just set pointer to symbol's bitmap
-       cv::Mat buf(symbol->bitmap_height, symbol->bitmap_width, CV_8UC3, symbol->bitmap);
-       changeColor(buf, config);
+       buf = cv::Mat(symbol->bitmap_height, symbol->bitmap_width, CV_8UC3, symbol->bitmap);
+       try {
+               drawDesignQR(buf, config);
+               changeColor(buf, config);
+       } catch (const std::exception &e) {
+               LOGE("Exception: %s", e.what());
+               return MEDIA_VISION_ERROR_INTERNAL;
+       } catch (...) {
+               LOGE("Unknown exception");
+               return MEDIA_VISION_ERROR_INTERNAL;
+       }
+       return MEDIA_VISION_ERROR_NONE;
+}
+
+int symbol_to_source(zint_symbol *symbol, const BarcodeConfig &config, mv_source_h source)
+{
+       cv::Mat buf;
+       MEDIA_VISION_CHECK_ERR(symbol_to_buf(symbol, config, buf), "symbol_to_buf failed");
        return mv_source_fill_by_buffer(source, buf.data, buf.total() * buf.elemSize(), buf.cols, buf.rows,
                                                                        MEDIA_VISION_COLORSPACE_RGB888);
 }
 
 int symbol_to_image(zint_symbol *symbol, const BarcodeConfig &config)
 {
-       int ret = mv_barcode_generate_symbol(symbol, config);
-       if (ret != MEDIA_VISION_ERROR_NONE) {
-               LOGE("mv_barcode_generate_symbol failed error : %d", ret);
-               return ret;
-       }
-
-       // This not copy data, just set pointer to symbol's bitmap
-       cv::Mat buf(symbol->bitmap_height, symbol->bitmap_width, CV_8UC3, symbol->bitmap);
-       changeColor(buf, config);
+       cv::Mat buf;
+       MEDIA_VISION_CHECK_ERR(symbol_to_buf(symbol, config, buf), "symbol_to_buf failed");
        return write_buffer_to_img(buf, config);
 }