mirror of
https://github.com/zint/zint
synced 2024-11-16 20:57:25 +13:00
gif.c: use malloc instead of alloca for LZW buffer as fails for large scale
This commit is contained in:
parent
537990e32e
commit
5766b39845
@ -41,7 +41,8 @@
|
|||||||
#include <malloc.h>
|
#include <malloc.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#define SSET "0123456789ABCDEF"
|
/* Limit initial ZLW buffer size to this in expectation that compressed data will fit for typical scalings */
|
||||||
|
#define GIF_ZLW_PAGE_SIZE 0x100000 /* Megabyte */
|
||||||
|
|
||||||
typedef struct s_statestruct {
|
typedef struct s_statestruct {
|
||||||
unsigned char *pOut;
|
unsigned char *pOut;
|
||||||
@ -95,8 +96,15 @@ static int BufferNextByte(statestruct *pState) {
|
|||||||
pState->OutByteCountPos = pState->OutPosCur;
|
pState->OutByteCountPos = pState->OutPosCur;
|
||||||
(pState->OutPosCur)++;
|
(pState->OutPosCur)++;
|
||||||
}
|
}
|
||||||
if (pState->OutPosCur >= pState->OutLength)
|
if (pState->OutPosCur >= pState->OutLength) {
|
||||||
return 1;
|
unsigned char *pOut;
|
||||||
|
pState->OutLength += GIF_ZLW_PAGE_SIZE;
|
||||||
|
/* Note pState->pOut not free()d by realloc() on failure */
|
||||||
|
if (!(pOut = (unsigned char *) realloc(pState->pOut, pState->OutLength))) {
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
pState->pOut = pOut;
|
||||||
|
}
|
||||||
|
|
||||||
(pState->pOut)[pState->OutPosCur] = 0x00;
|
(pState->pOut)[pState->OutPosCur] = 0x00;
|
||||||
return 0;
|
return 0;
|
||||||
@ -301,15 +309,9 @@ INTERNAL int gif_pixel_plot(struct zint_symbol *symbol, unsigned char *pixelbuf)
|
|||||||
|
|
||||||
/* Allow for overhead of 4 == code size + byte count + overflow byte + zero terminator */
|
/* Allow for overhead of 4 == code size + byte count + overflow byte + zero terminator */
|
||||||
unsigned int lzoutbufSize = bitmapSize + 4;
|
unsigned int lzoutbufSize = bitmapSize + 4;
|
||||||
#ifdef _MSC_VER
|
if (lzoutbufSize > GIF_ZLW_PAGE_SIZE) {
|
||||||
char *lzwoutbuf;
|
lzoutbufSize = GIF_ZLW_PAGE_SIZE;
|
||||||
#endif
|
}
|
||||||
|
|
||||||
#ifndef _MSC_VER
|
|
||||||
char lzwoutbuf[lzoutbufSize];
|
|
||||||
#else
|
|
||||||
lzwoutbuf = (char *) _alloca(lzoutbufSize);
|
|
||||||
#endif /* _MSC_VER */
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Build a table of the used palette items.
|
* Build a table of the used palette items.
|
||||||
@ -582,19 +584,27 @@ INTERNAL int gif_pixel_plot(struct zint_symbol *symbol, unsigned char *pixelbuf)
|
|||||||
/* prepare state array */
|
/* prepare state array */
|
||||||
State.pIn = pixelbuf;
|
State.pIn = pixelbuf;
|
||||||
State.InLen = bitmapSize;
|
State.InLen = bitmapSize;
|
||||||
State.pOut = (unsigned char *) lzwoutbuf;
|
if (!(State.pOut = (unsigned char *) malloc(lzoutbufSize))) {
|
||||||
|
if (!output_to_stdout) {
|
||||||
|
fclose(gif_file);
|
||||||
|
}
|
||||||
|
strcpy(symbol->errtxt, "614: Insufficient memory for LZW buffer");
|
||||||
|
return ZINT_ERROR_MEMORY;
|
||||||
|
}
|
||||||
State.OutLength = lzoutbufSize;
|
State.OutLength = lzoutbufSize;
|
||||||
|
|
||||||
/* call lzw encoding */
|
/* call lzw encoding */
|
||||||
byte_out = gif_lzw(&State, paletteBitSize);
|
byte_out = gif_lzw(&State, paletteBitSize);
|
||||||
if (byte_out <= 0) {
|
if (byte_out <= 0) {
|
||||||
|
free(State.pOut);
|
||||||
if (!output_to_stdout) {
|
if (!output_to_stdout) {
|
||||||
fclose(gif_file);
|
fclose(gif_file);
|
||||||
}
|
}
|
||||||
strcpy(symbol->errtxt, "613: Insufficient memory for LZW buffer");
|
strcpy(symbol->errtxt, "613: Insufficient memory for LZW buffer");
|
||||||
return ZINT_ERROR_MEMORY;
|
return ZINT_ERROR_MEMORY;
|
||||||
}
|
}
|
||||||
fwrite(lzwoutbuf, byte_out, 1, gif_file);
|
fwrite((const char *) State.pOut, byte_out, 1, gif_file);
|
||||||
|
free(State.pOut);
|
||||||
|
|
||||||
/* GIF terminator */
|
/* GIF terminator */
|
||||||
fputc('\x3b', gif_file);
|
fputc('\x3b', gif_file);
|
||||||
|
BIN
backend/tests/data/gif/itf14_height61.8_bind4_wsp24_3.gif
Normal file
BIN
backend/tests/data/gif/itf14_height61.8_bind4_wsp24_3.gif
Normal file
Binary file not shown.
After Width: | Height: | Size: 17 KiB |
@ -129,37 +129,40 @@ static void test_print(int index, int generate, int debug) {
|
|||||||
int whitespace_height;
|
int whitespace_height;
|
||||||
int option_1;
|
int option_1;
|
||||||
int option_2;
|
int option_2;
|
||||||
|
float height;
|
||||||
float scale;
|
float scale;
|
||||||
float dot_size;
|
float dot_size;
|
||||||
char *fgcolour;
|
char *fgcolour;
|
||||||
char *bgcolour;
|
char *bgcolour;
|
||||||
char *data;
|
char *data;
|
||||||
char *expected_file;
|
char *expected_file;
|
||||||
|
char *comment;
|
||||||
};
|
};
|
||||||
struct item data[] = {
|
struct item data[] = {
|
||||||
/* 0*/ { BARCODE_DOTCODE, -1, -1, -1, -1, -1, -1, 0, 0, "", "", "12", "dotcode_1.0.gif" },
|
/* 0*/ { BARCODE_DOTCODE, -1, -1, -1, -1, -1, -1, 0, 0, 0, "", "", "12", "dotcode_1.0.gif", "" },
|
||||||
/* 1*/ { BARCODE_DOTCODE, -1, -1, -1, -1, -1, -1, 0, 0.1, "", "", "12", "dotcode_1.0_ds0.1.gif" },
|
/* 1*/ { BARCODE_DOTCODE, -1, -1, -1, -1, -1, -1, 0, 0, 0.1, "", "", "12", "dotcode_1.0_ds0.1.gif", "" },
|
||||||
/* 2*/ { BARCODE_DOTCODE, -1, -1, -1, -1, -1, -1, 0, 1.1, "", "", "12", "dotcode_1.0_ds1.1.gif" },
|
/* 2*/ { BARCODE_DOTCODE, -1, -1, -1, -1, -1, -1, 0, 0, 1.1, "", "", "12", "dotcode_1.0_ds1.1.gif", "" },
|
||||||
/* 3*/ { BARCODE_DOTCODE, -1, -1, -1, -1, -1, -1, 1.5, 0, "", "", "12", "dotcode_1.5.gif" },
|
/* 3*/ { BARCODE_DOTCODE, -1, -1, -1, -1, -1, -1, 0, 1.5, 0, "", "", "12", "dotcode_1.5.gif", "" },
|
||||||
/* 4*/ { BARCODE_DOTCODE, -1, -1, -1, -1, -1, -1, 1.5, 0.4, "", "", "12", "dotcode_1.5_ds0.4.gif" },
|
/* 4*/ { BARCODE_DOTCODE, -1, -1, -1, -1, -1, -1, 0, 1.5, 0.4, "", "", "12", "dotcode_1.5_ds0.4.gif", "" },
|
||||||
/* 5*/ { BARCODE_DOTCODE, -1, -1, -1, -1, -1, -1, 1.5, 1.1, "", "", "12", "dotcode_1.5_ds1.1.gif" },
|
/* 5*/ { BARCODE_DOTCODE, -1, -1, -1, -1, -1, -1, 0, 1.5, 1.1, "", "", "12", "dotcode_1.5_ds1.1.gif", "" },
|
||||||
/* 6*/ { BARCODE_DOTCODE, -1, -1, -1, -1, -1, -1, 1.5, 2.1, "", "", "12", "dotcode_1.5_ds2.1.gif" },
|
/* 6*/ { BARCODE_DOTCODE, -1, -1, -1, -1, -1, -1, 0, 1.5, 2.1, "", "", "12", "dotcode_1.5_ds2.1.gif", "" },
|
||||||
/* 7*/ { BARCODE_DOTCODE, -1, -1, -1, -1, -1, -1, 2, 0, "", "", "12", "dotcode_2.0.gif" },
|
/* 7*/ { BARCODE_DOTCODE, -1, -1, -1, -1, -1, -1, 0, 2, 0, "", "", "12", "dotcode_2.0.gif", "" },
|
||||||
/* 8*/ { BARCODE_DOTCODE, -1, -1, -1, -1, -1, -1, 2, 0.9, "", "", "12", "dotcode_2.0_ds0.9.gif" },
|
/* 8*/ { BARCODE_DOTCODE, -1, -1, -1, -1, -1, -1, 0, 2, 0.9, "", "", "12", "dotcode_2.0_ds0.9.gif", "" },
|
||||||
/* 9*/ { BARCODE_DOTCODE, -1, -1, -1, -1, -1, -1, 2, 1.1, "", "", "12", "dotcode_2.0_ds1.1.gif" },
|
/* 9*/ { BARCODE_DOTCODE, -1, -1, -1, -1, -1, -1, 0, 2, 1.1, "", "", "12", "dotcode_2.0_ds1.1.gif", "" },
|
||||||
/* 10*/ { BARCODE_DOTCODE, -1, -1, -1, -1, -1, -1, 3, 0, "", "", "12", "dotcode_3.0.gif" },
|
/* 10*/ { BARCODE_DOTCODE, -1, -1, -1, -1, -1, -1, 0, 3, 0, "", "", "12", "dotcode_3.0.gif", "" },
|
||||||
/* 11*/ { BARCODE_DOTCODE, -1, -1, -1, -1, -1, -1, 3, 0.4, "", "", "12", "dotcode_3.0_ds0.4.gif" },
|
/* 11*/ { BARCODE_DOTCODE, -1, -1, -1, -1, -1, -1, 0, 3, 0.4, "", "", "12", "dotcode_3.0_ds0.4.gif", "" },
|
||||||
/* 12*/ { BARCODE_DOTCODE, -1, -1, -1, -1, -1, -1, 3, 1.1, "", "", "12", "dotcode_3.0_ds1.1.gif" },
|
/* 12*/ { BARCODE_DOTCODE, -1, -1, -1, -1, -1, -1, 0, 3, 1.1, "", "", "12", "dotcode_3.0_ds1.1.gif", "" },
|
||||||
/* 13*/ { BARCODE_DOTCODE, -1, -1, -1, -1, -1, -1, 3.5, 0, "", "", "12", "dotcode_3.5.gif" },
|
/* 13*/ { BARCODE_DOTCODE, -1, -1, -1, -1, -1, -1, 0, 3.5, 0, "", "", "12", "dotcode_3.5.gif", "" },
|
||||||
/* 14*/ { BARCODE_DOTCODE, -1, -1, -1, -1, -1, -1, 3.5, 0.4, "", "", "12", "dotcode_3.5_ds0.4.gif" },
|
/* 14*/ { BARCODE_DOTCODE, -1, -1, -1, -1, -1, -1, 0, 3.5, 0.4, "", "", "12", "dotcode_3.5_ds0.4.gif", "" },
|
||||||
/* 15*/ { BARCODE_DOTCODE, -1, -1, -1, -1, -1, -1, 3.5, 1.1, "", "", "12", "dotcode_3.5_ds1.1.gif" },
|
/* 15*/ { BARCODE_DOTCODE, -1, -1, -1, -1, -1, -1, 0, 3.5, 1.1, "", "", "12", "dotcode_3.5_ds1.1.gif", "" },
|
||||||
/* 16*/ { BARCODE_DOTCODE, -1, -1, -1, -1, -1, -1, 5, 0, "", "", "12", "dotcode_5.0.gif" },
|
/* 16*/ { BARCODE_DOTCODE, -1, -1, -1, -1, -1, -1, 0, 5, 0, "", "", "12", "dotcode_5.0.gif", "" },
|
||||||
/* 17*/ { BARCODE_DOTCODE, -1, -1, -1, -1, -1, -1, 5, 0.2, "", "", "12", "dotcode_5.0_ds0.2.gif" },
|
/* 17*/ { BARCODE_DOTCODE, -1, -1, -1, -1, -1, -1, 0, 5, 0.2, "", "", "12", "dotcode_5.0_ds0.2.gif", "" },
|
||||||
/* 18*/ { BARCODE_DOTCODE, -1, -1, -1, -1, -1, -1, 5, 1.1, "", "", "12", "dotcode_5.0_ds1.1.gif" },
|
/* 18*/ { BARCODE_DOTCODE, -1, -1, -1, -1, -1, -1, 0, 5, 1.1, "", "", "12", "dotcode_5.0_ds1.1.gif", "" },
|
||||||
/* 19*/ { BARCODE_DOTCODE, -1, -1, -1, -1, -1, -1, 5, 1.7, "", "", "12", "dotcode_5.0_ds1.7.gif" },
|
/* 19*/ { BARCODE_DOTCODE, -1, -1, -1, -1, -1, -1, 0, 5, 1.7, "", "", "12", "dotcode_5.0_ds1.7.gif", "" },
|
||||||
/* 20*/ { BARCODE_DOTCODE, -1, -1, -1, -1, -1, -1, 0, 0, "2674C344", "FDFFC2CC", "12", "dotcode_bgfgalpha.gif" },
|
/* 20*/ { BARCODE_DOTCODE, -1, -1, -1, -1, -1, -1, 0, 0, 0, "2674C344", "FDFFC2CC", "12", "dotcode_bgfgalpha.gif", "" },
|
||||||
/* 21*/ { BARCODE_DOTCODE, -1, -1, -1, -1, -1, -1, 0, 0, "00000000", "FFFFFF00", "12", "dotcode_bgfgtrans.gif" },
|
/* 21*/ { BARCODE_DOTCODE, -1, -1, -1, -1, -1, -1, 0, 0, 0, "00000000", "FFFFFF00", "12", "dotcode_bgfgtrans.gif", "" },
|
||||||
/* 22*/ { BARCODE_ULTRA, 1, BARCODE_BOX, 1, 1, -1, -1, 0, 0, "0000FF", "FF0000", "12", "ultra_fgbg_hvwsp1_box1.gif" },
|
/* 22*/ { BARCODE_ULTRA, 1, BARCODE_BOX, 1, 1, -1, -1, 0, 0, 0, "0000FF", "FF0000", "12", "ultra_fgbg_hvwsp1_box1.gif", "" },
|
||||||
|
/* 23*/ { BARCODE_ITF14, 4, BARCODE_BIND, 24, -1, -1, -1, 61.8, 3, 0, "", "", "0501054800395", "itf14_height61.8_bind4_wsp24_3.gif", "#204 ARM-Cortex crash" },
|
||||||
};
|
};
|
||||||
int data_size = ARRAY_SIZE(data);
|
int data_size = ARRAY_SIZE(data);
|
||||||
int i, length, ret;
|
int i, length, ret;
|
||||||
@ -201,6 +204,9 @@ static void test_print(int index, int generate, int debug) {
|
|||||||
if (data[i].whitespace_height != -1) {
|
if (data[i].whitespace_height != -1) {
|
||||||
symbol->whitespace_height = data[i].whitespace_height;
|
symbol->whitespace_height = data[i].whitespace_height;
|
||||||
}
|
}
|
||||||
|
if (data[i].height) {
|
||||||
|
symbol->height = data[i].height;
|
||||||
|
}
|
||||||
if (data[i].scale) {
|
if (data[i].scale) {
|
||||||
symbol->scale = data[i].scale;
|
symbol->scale = data[i].scale;
|
||||||
}
|
}
|
||||||
@ -224,11 +230,11 @@ static void test_print(int index, int generate, int debug) {
|
|||||||
assert_nonzero(testUtilDataPath(expected_file, sizeof(expected_file), data_dir, data[i].expected_file), "i:%d testUtilDataPath == 0\n", i);
|
assert_nonzero(testUtilDataPath(expected_file, sizeof(expected_file), data_dir, data[i].expected_file), "i:%d testUtilDataPath == 0\n", i);
|
||||||
|
|
||||||
if (generate) {
|
if (generate) {
|
||||||
printf(" /*%3d*/ { %s, %d, %s, %d, %d, %d, %d, %.5g, %.5g, \"%s\", \"%s\", \"%s\", \"%s\" },\n",
|
printf(" /*%3d*/ { %s, %d, %s, %d, %d, %d, %d, %.5g, %.5g, %.5g, \"%s\", \"%s\", \"%s\", \"%s\", \"%s\" },\n",
|
||||||
i, testUtilBarcodeName(data[i].symbology), data[i].border_width, testUtilOutputOptionsName(data[i].output_options),
|
i, testUtilBarcodeName(data[i].symbology), data[i].border_width, testUtilOutputOptionsName(data[i].output_options),
|
||||||
data[i].whitespace_width, data[i].whitespace_height,
|
data[i].whitespace_width, data[i].whitespace_height,
|
||||||
data[i].option_1, data[i].option_2, data[i].scale, data[i].dot_size, data[i].fgcolour, data[i].bgcolour,
|
data[i].option_1, data[i].option_2, data[i].height, data[i].scale, data[i].dot_size, data[i].fgcolour, data[i].bgcolour,
|
||||||
testUtilEscape(data[i].data, length, escaped, escaped_size), data[i].expected_file);
|
testUtilEscape(data[i].data, length, escaped, escaped_size), data[i].expected_file, data[i].comment);
|
||||||
ret = testUtilRename(symbol->outfile, expected_file);
|
ret = testUtilRename(symbol->outfile, expected_file);
|
||||||
assert_zero(ret, "i:%d testUtilRename(%s, %s) ret %d != 0\n", i, symbol->outfile, expected_file, ret);
|
assert_zero(ret, "i:%d testUtilRename(%s, %s) ret %d != 0\n", i, symbol->outfile, expected_file, ret);
|
||||||
if (have_identify) {
|
if (have_identify) {
|
||||||
@ -275,12 +281,43 @@ static void test_outfile(void) {
|
|||||||
testFinish();
|
testFinish();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void test_large_scale(int debug) {
|
||||||
|
int length, ret;
|
||||||
|
struct zint_symbol symbol = {0};
|
||||||
|
char data[] = "1";
|
||||||
|
|
||||||
|
testStart("test_large_scale");
|
||||||
|
|
||||||
|
length = (int) strlen(data);
|
||||||
|
|
||||||
|
symbol.symbology = BARCODE_ITF14;
|
||||||
|
strcpy(symbol.fgcolour, "000000");
|
||||||
|
strcpy(symbol.bgcolour, "ffffff");
|
||||||
|
strcpy(symbol.outfile, "out.gif");
|
||||||
|
// X-dimension 0.27mm * 95 = 25.65 ~ 25 pixels so 12.5 gives 95 dpmm (2400 dpi)
|
||||||
|
symbol.scale = 12.5f; // 70.0f would cause re-alloc as LZW > 1MB but very slow
|
||||||
|
symbol.dot_size = 4.0f / 5.0f;
|
||||||
|
|
||||||
|
ret = ZBarcode_Encode_and_Print(&symbol, (unsigned char *) data, length, 0 /*rotate_angle*/);
|
||||||
|
assert_zero(ret, "%s ZBarcode_Encode_and_Print ret %d != 0 %s\n", testUtilBarcodeName(symbol.symbology), ret, symbol.errtxt);
|
||||||
|
|
||||||
|
if (!(debug & ZINT_DEBUG_TEST_KEEP_OUTFILE)) { /* -d 64 */
|
||||||
|
// 129.1 kB file manually inspected and checked (1.1 MB file for scale 70.0f also checked)
|
||||||
|
assert_zero(remove(symbol.outfile), "remove(%s) != 0\n", symbol.outfile);
|
||||||
|
}
|
||||||
|
|
||||||
|
ZBarcode_Clear(&symbol);
|
||||||
|
|
||||||
|
testFinish();
|
||||||
|
}
|
||||||
|
|
||||||
int main(int argc, char *argv[]) {
|
int main(int argc, char *argv[]) {
|
||||||
|
|
||||||
testFunction funcs[] = { /* name, func, has_index, has_generate, has_debug */
|
testFunction funcs[] = { /* name, func, has_index, has_generate, has_debug */
|
||||||
{ "test_pixel_plot", test_pixel_plot, 1, 0, 1 },
|
{ "test_pixel_plot", test_pixel_plot, 1, 0, 1 },
|
||||||
{ "test_print", test_print, 1, 1, 1 },
|
{ "test_print", test_print, 1, 1, 1 },
|
||||||
{ "test_outfile", test_outfile, 0, 0, 0 },
|
{ "test_outfile", test_outfile, 0, 0, 0 },
|
||||||
|
{ "test_large_scale", test_large_scale, 0, 0, 1 },
|
||||||
};
|
};
|
||||||
|
|
||||||
testRun(argc, argv, funcs, ARRAY_SIZE(funcs));
|
testRun(argc, argv, funcs, ARRAY_SIZE(funcs));
|
||||||
|
Loading…
Reference in New Issue
Block a user