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 {
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);
}