1
0
mirror of https://git.code.sf.net/p/zint/code synced 2026-06-09 23:23:36 +00:00

raster/vector: allow for separator height being > twice row height

(ticket #353, props Simon Resch)
This commit is contained in:
gitlost
2026-03-19 17:52:12 +00:00
parent d7b0daae5b
commit f6174cba04
5 changed files with 95 additions and 37 deletions
+2 -2
View File
@@ -1,7 +1,7 @@
/* output.c - Common routines for raster/vector /* output.c - Common routines for raster/vector
libzint - the open source barcode library libzint - the open source barcode library
Copyright (C) 2020-2025 Robin Stuart <rstuart114@gmail.com> Copyright (C) 2020-2026 Robin Stuart <rstuart114@gmail.com>
Redistribution and use in source and binary forms, with or without Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions modification, are permitted provided that the following conditions
@@ -846,7 +846,7 @@ INTERNAL float zint_out_large_bar_height(struct zint_symbol *symbol, const int s
large_bar_height = z_stripf(roundf(large_bar_height * si) / si); large_bar_height = z_stripf(roundf(large_bar_height * si) / si);
} }
symbol->height = z_stripf(large_bar_height * zero_count + fixed_height); symbol->height = z_stripf(large_bar_height * zero_count + fixed_height);
/* Note should never happen that have both zero_count and round_rows */ /* Note should never happen that have both zero_count and round_rows */
} else { } else {
if (round_rows) { if (round_rows) {
float total_height = 0.0f; float total_height = 0.0f;
+17 -1
View File
@@ -1,7 +1,7 @@
/* raster.c - Handles output to raster files */ /* raster.c - Handles output to raster files */
/* /*
libzint - the open source barcode library libzint - the open source barcode library
Copyright (C) 2009-2025 Robin Stuart <rstuart114@gmail.com> Copyright (C) 2009-2026 Robin Stuart <rstuart114@gmail.com>
Redistribution and use in source and binary forms, with or without Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions modification, are permitted provided that the following conditions
@@ -290,6 +290,10 @@ static void draw_bar_line(unsigned char *pixelbuf, const int xpos, const int xle
const int image_width, const int fill) { const int image_width, const int fill) {
unsigned char *pb = pixelbuf + ((size_t) image_width * ypos) + xpos; unsigned char *pb = pixelbuf + ((size_t) image_width * ypos) + xpos;
assert(xpos >= 0);
assert(xlen >= 0);
assert(ypos >= 0);
memset(pb, fill, xlen); memset(pb, fill, xlen);
} }
@@ -300,6 +304,10 @@ static void copy_bar_line(unsigned char *pixelbuf, const int xpos, const int xle
const int ye = ypos + ylen > image_height ? image_height : ypos + ylen; /* Defensive, should never happen */ const int ye = ypos + ylen > image_height ? image_height : ypos + ylen; /* Defensive, should never happen */
unsigned char *pb = pixelbuf + ((size_t) image_width * ypos) + xpos; unsigned char *pb = pixelbuf + ((size_t) image_width * ypos) + xpos;
assert(xpos >= 0);
assert(xlen >= 0);
assert(ypos >= 0);
assert(ylen >= 0);
assert(ypos + ylen <= image_height); /* Trigger assert if "should never happen" happens */ assert(ypos + ylen <= image_height); /* Trigger assert if "should never happen" happens */
for (y = ypos + 1; y < ye; y++) { for (y = ypos + 1; y < ye; y++) {
@@ -314,6 +322,10 @@ static void draw_bar(unsigned char *pixelbuf, const int xpos, const int xlen, co
const int ye = ypos + ylen > image_height ? image_height : ypos + ylen; /* Defensive, should never happen */ const int ye = ypos + ylen > image_height ? image_height : ypos + ylen; /* Defensive, should never happen */
unsigned char *pb = pixelbuf + ((size_t) image_width * ypos) + xpos; unsigned char *pb = pixelbuf + ((size_t) image_width * ypos) + xpos;
assert(xpos >= 0);
assert(xlen >= 0);
assert(ypos >= 0);
assert(ylen >= 0);
assert(ypos + ylen <= image_height); /* Trigger assert if "should never happen" happens */ assert(ypos + ylen <= image_height); /* Trigger assert if "should never happen" happens */
for (y = ypos; y < ye; y++, pb += image_width) { for (y = ypos; y < ye; y++, pb += image_width) {
@@ -1354,11 +1366,15 @@ static int plot_raster_default(struct zint_symbol *symbol, const int rotate_angl
sep_height = symbol->option_3; sep_height = symbol->option_3;
} }
sep_height_si = (int) (sep_height * si); sep_height_si = (int) (sep_height * si);
if (sep_height_si > row_heights_si[0] * 2) { /* Ticket 353, props Simon Resch */
sep_height_si = row_heights_si[0] * 2;
}
sep_yoffset_si = yoffset_si + row_heights_si[0] - sep_height_si / 2; sep_yoffset_si = yoffset_si + row_heights_si[0] - sep_height_si / 2;
if (is_codablockf) { if (is_codablockf) {
/* Avoid 11-module start and 13-module stop chars */ /* Avoid 11-module start and 13-module stop chars */
sep_xoffset_si += 11 * si; sep_xoffset_si += 11 * si;
sep_width_si -= (11 + 13) * si; sep_width_si -= (11 + 13) * si;
assert(sep_width_si >= 0);
} }
for (r = 1; r < symbol->rows; r++) { for (r = 1; r < symbol->rows; r++) {
draw_bar(pixelbuf, sep_xoffset_si, sep_width_si, sep_yoffset_si, sep_height_si, image_width, image_height, draw_bar(pixelbuf, sep_xoffset_si, sep_width_si, sep_yoffset_si, sep_height_si, image_width, image_height,
+26 -17
View File
@@ -742,6 +742,7 @@ static void test_row_separator(const testCtx *const p_ctx) {
int border_width; int border_width;
int option_1; int option_1;
int option_3; int option_3;
float height;
const char *data; const char *data;
int ret; int ret;
@@ -756,15 +757,18 @@ static void test_row_separator(const testCtx *const p_ctx) {
}; };
/* s/\/\*[ 0-9]*\*\//\=printf("\/\*%3d*\/", line(".") - line("'<")): */ /* s/\/\*[ 0-9]*\*\//\=printf("\/\*%3d*\/", line(".") - line("'<")): */
static const struct item data[] = { static const struct item data[] = {
/* 0*/ { BARCODE_CODABLOCKF, -1, -1, -1, "A", 0, 20, 2, 101, 242, 44, 21, 42, 2 }, /* 0*/ { BARCODE_CODABLOCKF, -1, -1, -1, 0, "A", 0, 20, 2, 101, 242, 44, 21, 42, 2 },
/* 1*/ { BARCODE_CODABLOCKF, -1, -1, 0, "A", 0, 20, 2, 101, 242, 44, 21, 42, 2 }, /* Same as default */ /* 1*/ { BARCODE_CODABLOCKF, -1, -1, 0, 0, "A", 0, 20, 2, 101, 242, 44, 21, 42, 2 }, /* Same as default */
/* 2*/ { BARCODE_CODABLOCKF, -1, -1, 1, "A", 0, 20, 2, 101, 242, 44, 21, 42, 2 }, /* Same as default */ /* 2*/ { BARCODE_CODABLOCKF, -1, -1, 1, 0, "A", 0, 20, 2, 101, 242, 44, 21, 42, 2 }, /* Same as default */
/* 3*/ { BARCODE_CODABLOCKF, -1, -1, 2, "A", 0, 20, 2, 101, 242, 44, 20, 42, 4 }, /* 3*/ { BARCODE_CODABLOCKF, -1, -1, 2, 0, "A", 0, 20, 2, 101, 242, 44, 20, 42, 4 },
/* 4*/ { BARCODE_CODABLOCKF, -1, -1, 3, "A", 0, 20, 2, 101, 242, 44, 19, 42, 6 }, /* 4*/ { BARCODE_CODABLOCKF, -1, -1, 3, 0, "A", 0, 20, 2, 101, 242, 44, 19, 42, 6 },
/* 5*/ { BARCODE_CODABLOCKF, -1, -1, 4, "A", 0, 20, 2, 101, 242, 44, 18, 42, 8 }, /* 5*/ { BARCODE_CODABLOCKF, -1, -1, 4, 0, "A", 0, 20, 2, 101, 242, 44, 18, 42, 8 },
/* 6*/ { BARCODE_CODABLOCKF, -1, -1, 5, "A", 0, 20, 2, 101, 242, 44, 21, 42, 2 }, /* > 4 ignored, same as default */ /* 6*/ { BARCODE_CODABLOCKF, -1, -1, 5, 0, "A", 0, 20, 2, 101, 242, 44, 21, 42, 2 }, /* > 4 ignored, same as default */
/* 7*/ { BARCODE_CODABLOCKF, -1, 1, -1, "A", 0, 5, 1, 46, 132, 14, 0, 20 + 2, 2 }, /* CODE128 top separator, add 2 to skip over end of start char; note no longer includes HRT */ /* 7*/ { BARCODE_CODABLOCKF, -1, 1, -1, 0, "A", 0, 5, 1, 46, 132, 14, 0, 20 + 2, 2 }, /* CODE128 top separator, add 2 to skip over end of start char; note no longer includes HRT */
/* 8*/ { BARCODE_CODABLOCKF, 0, -1, -1, "A", 0, 20, 2, 101, 242, 44, 21, 42, 2 }, /* Border width zero, same as default */ /* 8*/ { BARCODE_CODABLOCKF, 0, -1, -1, 0, "A", 0, 20, 2, 101, 242, 44, 21, 42, 2 }, /* Border width zero, same as default */
/* 9*/ { BARCODE_CODABLOCKF, -1, -1, 4, 2, "A", 0, 2, 2, 101, 242, 8, 0, 42, 8 }, /* Ticket #353, props Simon Resch */
/* 10*/ { BARCODE_CODABLOCKF, -1, -1, 4, 1.5, "A", 0, 2, 2, 101, 242, 8, 0, 42, 8 }, /* Height gets rounded up as not integral */
/* 11*/ { BARCODE_CODABLOCKF, -1, -1, 4, 1, "A", 0, 1, 2, 101, 242, 6, 0, 42, 6 },
}; };
const int data_size = ARRAY_SIZE(data); const int data_size = ARRAY_SIZE(data);
int i, length, ret; int i, length, ret;
@@ -785,6 +789,9 @@ static void test_row_separator(const testCtx *const p_ctx) {
if (data[i].border_width != -1) { if (data[i].border_width != -1) {
symbol->border_width = data[i].border_width; symbol->border_width = data[i].border_width;
} }
if (data[i].height) {
symbol->height = data[i].height;
}
ret = ZBarcode_Encode_and_Buffer(symbol, (unsigned char *) data[i].data, length, 0); ret = ZBarcode_Encode_and_Buffer(symbol, (unsigned char *) data[i].data, length, 0);
assert_equal(ret, data[i].ret, "i:%d ret %d != %d (%s)\n", i, ret, data[i].ret, symbol->errtxt); assert_equal(ret, data[i].ret, "i:%d ret %d != %d (%s)\n", i, ret, data[i].ret, symbol->errtxt);
@@ -805,15 +812,17 @@ static void test_row_separator(const testCtx *const p_ctx) {
assert_nonzero(separator_bits_set, "i:%d (%s) separator_bits_set (%d, %d) zero\n", i, testUtilBarcodeName(data[i].symbology), j, data[i].expected_separator_col); assert_nonzero(separator_bits_set, "i:%d (%s) separator_bits_set (%d, %d) zero\n", i, testUtilBarcodeName(data[i].symbology), j, data[i].expected_separator_col);
} }
if (symbol->rows > 1) { if (data[i].expected_separator_row > 0) {
j = data[i].expected_separator_row - 1; if (symbol->rows > 1) {
separator_bits_set = is_row_column_black(symbol, j, data[i].expected_separator_col + 2); /* Need to add 2 to skip to 1st blank of start row character */ j = data[i].expected_separator_row - 1;
assert_zero(separator_bits_set, "i:%d (%s) separator_bits_set (%d, %d) before non-zero\n", i, testUtilBarcodeName(data[i].symbology), j, data[i].expected_separator_col); separator_bits_set = is_row_column_black(symbol, j, data[i].expected_separator_col + 2); /* Need to add 2 to skip to 1st blank of start row character */
} assert_zero(separator_bits_set, "i:%d (%s) separator_bits_set (%d, %d) before non-zero\n", i, testUtilBarcodeName(data[i].symbology), j, data[i].expected_separator_col);
}
j = data[i].expected_separator_row + data[i].expected_separator_height; j = data[i].expected_separator_row + data[i].expected_separator_height;
separator_bits_set = is_row_column_black(symbol, j, data[i].expected_separator_col + 2); /* Need to add 2 to skip to 1st blank of start row character */ separator_bits_set = is_row_column_black(symbol, j, data[i].expected_separator_col + 2); /* Need to add 2 to skip to 1st blank of start row character */
assert_zero(separator_bits_set, "i:%d (%s) separator_bits_set (%d, %d) after non-zero\n", i, testUtilBarcodeName(data[i].symbology), j, data[i].expected_separator_col); assert_zero(separator_bits_set, "i:%d (%s) separator_bits_set (%d, %d) after non-zero\n", i, testUtilBarcodeName(data[i].symbology), j, data[i].expected_separator_col);
}
ZBarcode_Delete(symbol); ZBarcode_Delete(symbol);
} }
+25 -14
View File
@@ -1123,7 +1123,7 @@ static void test_upcean_hrt(const testCtx *const p_ctx) {
i, testUtilBarcodeName(data[i].symbology), symbol->vector->height, i, testUtilBarcodeName(data[i].symbology), symbol->vector->height,
data[i].expected_vector_height); data[i].expected_vector_height);
if (p_ctx->index != -1 && (debug & ZINT_DEBUG_TEST_PRINT)) { if (p_ctx->index != -1 && (debug & ZINT_DEBUG_TEST_PRINT)) { /* ZINT_DEBUG_TEST_PRINT 16 */
testUtilVectorPrint(symbol); testUtilVectorPrint(symbol);
} }
@@ -1165,6 +1165,7 @@ static void test_row_separator(const testCtx *const p_ctx) {
int border_width; int border_width;
int option_1; int option_1;
int option_3; int option_3;
float height;
const char *data; const char *data;
int ret; int ret;
@@ -1177,15 +1178,18 @@ static void test_row_separator(const testCtx *const p_ctx) {
}; };
/* s/\/\*[ 0-9]*\*\//\=printf("\/\*%3d*\/", line(".") - line("'<")): */ /* s/\/\*[ 0-9]*\*\//\=printf("\/\*%3d*\/", line(".") - line("'<")): */
struct item data[] = { struct item data[] = {
/* 0*/ { BARCODE_CODABLOCKF, -1, -1, -1, "A", 0, 20, 2, 101, 42, 21, 2 }, /* 0*/ { BARCODE_CODABLOCKF, -1, -1, -1, 0, "A", 0, 20, 2, 101, 42, 21, 2 },
/* 1*/ { BARCODE_CODABLOCKF, -1, -1, 0, "A", 0, 20, 2, 101, 42, 21, 2 }, /* Same as default */ /* 1*/ { BARCODE_CODABLOCKF, -1, -1, 0, 0, "A", 0, 20, 2, 101, 42, 21, 2 }, /* Same as default */
/* 2*/ { BARCODE_CODABLOCKF, -1, -1, 1, "A", 0, 20, 2, 101, 42, 21, 2 }, /* Same as default */ /* 2*/ { BARCODE_CODABLOCKF, -1, -1, 1, 0, "A", 0, 20, 2, 101, 42, 21, 2 }, /* Same as default */
/* 3*/ { BARCODE_CODABLOCKF, -1, -1, 2, "A", 0, 20, 2, 101, 42, 20, 4 }, /* 3*/ { BARCODE_CODABLOCKF, -1, -1, 2, 0, "A", 0, 20, 2, 101, 42, 20, 4 },
/* 4*/ { BARCODE_CODABLOCKF, -1, -1, 3, "A", 0, 20, 2, 101, 42, 19, 6 }, /* 4*/ { BARCODE_CODABLOCKF, -1, -1, 3, 0, "A", 0, 20, 2, 101, 42, 19, 6 },
/* 5*/ { BARCODE_CODABLOCKF, -1, -1, 4, "A", 0, 20, 2, 101, 42, 18, 8 }, /* 5*/ { BARCODE_CODABLOCKF, -1, -1, 4, 0, "A", 0, 20, 2, 101, 42, 18, 8 },
/* 6*/ { BARCODE_CODABLOCKF, -1, -1, 5, "A", 0, 20, 2, 101, 42, 21, 2 }, /* > 4 ignored, same as default */ /* 6*/ { BARCODE_CODABLOCKF, -1, -1, 5, 0, "A", 0, 20, 2, 101, 42, 21, 2 }, /* > 4 ignored, same as default */
/* 7*/ { BARCODE_CODABLOCKF, -1, 1, -1, "A", 0, 5, 1, 46, 20, 0, 2 }, /* CODE128 top separator */ /* 7*/ { BARCODE_CODABLOCKF, -1, 1, -1, 0, "A", 0, 5, 1, 46, 20, 0, 2 }, /* CODE128 top separator */
/* 8*/ { BARCODE_CODABLOCKF, 0, -1, -1, "A", 0, 20, 2, 101, 42, 21, 2 }, /* Border width zero, same as default */ /* 8*/ { BARCODE_CODABLOCKF, 0, -1, -1, 0, "A", 0, 20, 2, 101, 42, 21, 2 }, /* Border width zero, same as default */
/* 9*/ { BARCODE_CODABLOCKF, -1, -1, 4, 2, "A", 0, 2, 2, 101, 42, 0, 8 }, /* Ticket #353, props Simon Resch */
/* 10*/ { BARCODE_CODABLOCKF, -1, -1, 4, 1.5, "A", 0, 1.5, 2, 101, 42, 0, 8 },
/* 11*/ { BARCODE_CODABLOCKF, -1, -1, 4, 1, "A", 0, 1, 2, 101, 42, 0, 8 },
}; };
int data_size = ARRAY_SIZE(data); int data_size = ARRAY_SIZE(data);
int i, length, ret; int i, length, ret;
@@ -1206,6 +1210,9 @@ static void test_row_separator(const testCtx *const p_ctx) {
if (data[i].border_width != -1) { if (data[i].border_width != -1) {
symbol->border_width = data[i].border_width; symbol->border_width = data[i].border_width;
} }
if (data[i].height) {
symbol->height = data[i].height;
}
ret = ZBarcode_Encode(symbol, TCU(data[i].data), length); ret = ZBarcode_Encode(symbol, TCU(data[i].data), length);
assert_zero(ret, "i:%d ZBarcode_Encode(%d) ret %d != 0 %s\n", i, data[i].symbology, ret, symbol->errtxt); assert_zero(ret, "i:%d ZBarcode_Encode(%d) ret %d != 0 %s\n", i, data[i].symbology, ret, symbol->errtxt);
@@ -1214,6 +1221,10 @@ static void test_row_separator(const testCtx *const p_ctx) {
assert_zero(ret, "i:%d ZBarcode_Buffer_Vector(%d) ret %d != 0\n", i, data[i].symbology, ret); assert_zero(ret, "i:%d ZBarcode_Buffer_Vector(%d) ret %d != 0\n", i, data[i].symbology, ret);
assert_nonnull(symbol->vector, "i:%d ZBarcode_Buffer_Vector(%d) vector NULL\n", i, data[i].symbology); assert_nonnull(symbol->vector, "i:%d ZBarcode_Buffer_Vector(%d) vector NULL\n", i, data[i].symbology);
if (p_ctx->index != -1 && (debug & ZINT_DEBUG_TEST_PRINT)) { /* ZINT_DEBUG_TEST_PRINT 16 */
testUtilVectorPrint(symbol);
}
assert_equal(symbol->height, data[i].expected_height, "i:%d (%d) symbol->height %.9g != %.9g\n", i, data[i].symbology, symbol->height, data[i].expected_height); assert_equal(symbol->height, data[i].expected_height, "i:%d (%d) symbol->height %.9g != %.9g\n", i, data[i].symbology, symbol->height, data[i].expected_height);
assert_equal(symbol->rows, data[i].expected_rows, "i:%d (%d) symbol->rows %d != %d\n", i, data[i].symbology, symbol->rows, data[i].expected_rows); assert_equal(symbol->rows, data[i].expected_rows, "i:%d (%d) symbol->rows %d != %d\n", i, data[i].symbology, symbol->rows, data[i].expected_rows);
assert_equal(symbol->width, data[i].expected_width, "i:%d (%d) symbol->width %d != %d\n", i, data[i].symbology, symbol->width, data[i].expected_width); assert_equal(symbol->width, data[i].expected_width, "i:%d (%d) symbol->width %d != %d\n", i, data[i].symbology, symbol->width, data[i].expected_width);
@@ -1286,7 +1297,7 @@ static void test_stacking(const testCtx *const p_ctx) {
assert_equal(symbol->width, data[i].expected_width, "i:%d (%d) symbol->width %d != %d\n", i, data[i].symbology, symbol->width, data[i].expected_width); assert_equal(symbol->width, data[i].expected_width, "i:%d (%d) symbol->width %d != %d\n", i, data[i].symbology, symbol->width, data[i].expected_width);
if (data[i].expected_separator_y != -1) { if (data[i].expected_separator_y != -1) {
if (p_ctx->index != -1 && (debug & ZINT_DEBUG_TEST_PRINT)) { if (p_ctx->index != -1 && (debug & ZINT_DEBUG_TEST_PRINT)) { /* ZINT_DEBUG_TEST_PRINT 16 */
testUtilVectorPrint(symbol); testUtilVectorPrint(symbol);
} }
@@ -1424,7 +1435,7 @@ static void test_output_options(const testCtx *const p_ctx) {
if (ret < ZINT_ERROR) { if (ret < ZINT_ERROR) {
assert_nonnull(symbol->vector, "i:%d ZBarcode_Buffer_Vector(%d) vector NULL\n", i, data[i].symbology); assert_nonnull(symbol->vector, "i:%d ZBarcode_Buffer_Vector(%d) vector NULL\n", i, data[i].symbology);
if (p_ctx->index != -1 && (debug & ZINT_DEBUG_TEST_PRINT)) { if (p_ctx->index != -1 && (debug & ZINT_DEBUG_TEST_PRINT)) { /* ZINT_DEBUG_TEST_PRINT 16 */
testUtilVectorPrint(symbol); testUtilVectorPrint(symbol);
} }
@@ -1558,7 +1569,7 @@ static void test_upcean_whitespace_width(const testCtx *const p_ctx) {
assert_zero(ret, "i:%d ZBarcode_Buffer_Vector(%d) ret %d != 0\n", i, data[i].symbology, ret); assert_zero(ret, "i:%d ZBarcode_Buffer_Vector(%d) ret %d != 0\n", i, data[i].symbology, ret);
assert_nonnull(symbol->vector, "i:%d ZBarcode_Buffer_Vector(%d) vector NULL\n", i, data[i].symbology); assert_nonnull(symbol->vector, "i:%d ZBarcode_Buffer_Vector(%d) vector NULL\n", i, data[i].symbology);
if (p_ctx->index != -1 && (debug & ZINT_DEBUG_TEST_PRINT)) { if (p_ctx->index != -1 && (debug & ZINT_DEBUG_TEST_PRINT)) { /* ZINT_DEBUG_TEST_PRINT 16 */
testUtilVectorPrint(symbol); testUtilVectorPrint(symbol);
} }
@@ -1656,7 +1667,7 @@ static void test_scale(const testCtx *const p_ctx) {
assert_equal(ret, data[i].ret_vector, "i:%d ZBarcode_Buffer_Vector(%d) ret %d != %d (%s)\n", i, data[i].symbology, ret, data[i].ret_vector, symbol->errtxt); assert_equal(ret, data[i].ret_vector, "i:%d ZBarcode_Buffer_Vector(%d) ret %d != %d (%s)\n", i, data[i].symbology, ret, data[i].ret_vector, symbol->errtxt);
assert_nonnull(symbol->vector, "i:%d ZBarcode_Buffer_Vector(%d) vector NULL\n", i, data[i].symbology); assert_nonnull(symbol->vector, "i:%d ZBarcode_Buffer_Vector(%d) vector NULL\n", i, data[i].symbology);
if (p_ctx->index != -1 && (debug & ZINT_DEBUG_TEST_PRINT)) { if (p_ctx->index != -1 && (debug & ZINT_DEBUG_TEST_PRINT)) { /* ZINT_DEBUG_TEST_PRINT 16 */
testUtilVectorPrint(symbol); testUtilVectorPrint(symbol);
} }
+25 -3
View File
@@ -1,7 +1,7 @@
/* vector.c - Creates vector image objects */ /* vector.c - Creates vector image objects */
/* /*
libzint - the open source barcode library libzint - the open source barcode library
Copyright (C) 2018-2025 Robin Stuart <rstuart114@gmail.com> Copyright (C) 2018-2026 Robin Stuart <rstuart114@gmail.com>
Redistribution and use in source and binary forms, with or without Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions modification, are permitted provided that the following conditions
@@ -30,6 +30,8 @@
*/ */
/* SPDX-License-Identifier: BSD-3-Clause */ /* SPDX-License-Identifier: BSD-3-Clause */
#include <assert.h>
#include "common.h" #include "common.h"
#include "output.h" #include "output.h"
#include "zfiletypes.h" #include "zfiletypes.h"
@@ -42,6 +44,11 @@ static int vector_add_rect(struct zint_symbol *symbol, const float x, const floa
const float height, struct zint_vector_rect **last_rect) { const float height, struct zint_vector_rect **last_rect) {
struct zint_vector_rect *rect; struct zint_vector_rect *rect;
assert(x >= 0.0f);
assert(y >= 0.0f);
assert(width >= 0.0f);
assert(height >= 0.0f);
if (!(rect = (struct zint_vector_rect *) malloc(sizeof(struct zint_vector_rect)))) { if (!(rect = (struct zint_vector_rect *) malloc(sizeof(struct zint_vector_rect)))) {
/* NOTE: clang-tidy-20 gets confused about return value of function returning a function unfortunately, /* NOTE: clang-tidy-20 gets confused about return value of function returning a function unfortunately,
so put on 2 lines (see also "postal.c" `postnet_enc()` & `planet_enc()`, same issue) */ so put on 2 lines (see also "postal.c" `postnet_enc()` & `planet_enc()`, same issue) */
@@ -73,6 +80,10 @@ static int vector_add_hexagon(struct zint_symbol *symbol, const float x, const f
const float diameter, struct zint_vector_hexagon **last_hexagon) { const float diameter, struct zint_vector_hexagon **last_hexagon) {
struct zint_vector_hexagon *hexagon; struct zint_vector_hexagon *hexagon;
assert(x >= 0.0f);
assert(y >= 0.0f);
assert(diameter >= 0.0f);
if (!(hexagon = (struct zint_vector_hexagon *) malloc(sizeof(struct zint_vector_hexagon)))) { if (!(hexagon = (struct zint_vector_hexagon *) malloc(sizeof(struct zint_vector_hexagon)))) {
return z_errtxt(0, symbol, 692, "Insufficient memory for vector hexagon"); return z_errtxt(0, symbol, 692, "Insufficient memory for vector hexagon");
} }
@@ -99,6 +110,11 @@ static int vector_add_circle(struct zint_symbol *symbol, const float x, const fl
const float width, const int colour, struct zint_vector_circle **last_circle) { const float width, const int colour, struct zint_vector_circle **last_circle) {
struct zint_vector_circle *circle; struct zint_vector_circle *circle;
assert(x >= 0.0f);
assert(y >= 0.0f);
assert(diameter >= 0.0f);
assert(width >= 0.0f);
if (!(circle = (struct zint_vector_circle *) malloc(sizeof(struct zint_vector_circle)))) { if (!(circle = (struct zint_vector_circle *) malloc(sizeof(struct zint_vector_circle)))) {
return z_errtxt(0, symbol, 693, "Insufficient memory for vector circle"); return z_errtxt(0, symbol, 693, "Insufficient memory for vector circle");
} }
@@ -127,6 +143,10 @@ static int vector_add_string(struct zint_symbol *symbol, const unsigned char *te
struct zint_vector_string **last_string) { struct zint_vector_string **last_string) {
struct zint_vector_string *string; struct zint_vector_string *string;
assert(x >= -0.5f); /* May be slightly negative due to fudging */
assert(y >= 0.0f);
assert(width >= 0.0f);
if (!(string = (struct zint_vector_string *) malloc(sizeof(struct zint_vector_string)))) { if (!(string = (struct zint_vector_string *) malloc(sizeof(struct zint_vector_string)))) {
return z_errtxt(0, symbol, 694, "Insufficient memory for vector string"); return z_errtxt(0, symbol, 694, "Insufficient memory for vector string");
} }
@@ -934,6 +954,7 @@ INTERNAL int zint_plot_vector(struct zint_symbol *symbol, int rotate_angle, int
/* Avoid 11-module start and 13-module stop chars */ /* Avoid 11-module start and 13-module stop chars */
sep_xoffset += 11; sep_xoffset += 11;
sep_width -= 11 + 13; sep_width -= 11 + 13;
assert(sep_width >= 0.0f);
} }
/* Adjust original rectangles so don't overlap with separator(s) (important for RGBA) */ /* Adjust original rectangles so don't overlap with separator(s) (important for RGBA) */
for (r = 0; r < symbol->rows; r++) { for (r = 0; r < symbol->rows; r++) {
@@ -952,7 +973,7 @@ INTERNAL int zint_plot_vector(struct zint_symbol *symbol, int rotate_angle, int
} else { } else {
rect->height -= sep_half_height; rect->height -= sep_half_height;
} }
if (rect->height < 0) { if (rect->height < 0.0f) {
rect->height = 0.0f; rect->height = 0.0f;
/* TODO: warn? */ /* TODO: warn? */
} }
@@ -960,7 +981,8 @@ INTERNAL int zint_plot_vector(struct zint_symbol *symbol, int rotate_angle, int
} }
for (r = 1; r < symbol->rows; r++) { for (r = 1; r < symbol->rows; r++) {
const float row_height = symbol->row_height[r - 1] ? symbol->row_height[r - 1] : large_bar_height; const float row_height = symbol->row_height[r - 1] ? symbol->row_height[r - 1] : large_bar_height;
if (!vector_add_rect(symbol, sep_xoffset, (r * row_height) + sep_yoffset, sep_width, sep_height, const float y = (r * row_height) + sep_yoffset;
if (!vector_add_rect(symbol, sep_xoffset, y < 0.0f ? 0.0f : y, sep_width, sep_height,
&last_rect)) return ZINT_ERROR_MEMORY; &last_rect)) return ZINT_ERROR_MEMORY;
} }
} }