From 4bd8abf8ab9ce47d2fe36013bdc009010e3d1ac4 Mon Sep 17 00:00:00 2001 From: kikuchan Date: Mon, 22 Jan 2024 11:45:10 +0900 Subject: [PATCH] Make image/detector malloc free --- Makefile | 27 ++++++--- cli/qrean-detect/qrean-detect.c | 33 ++++++----- cli/qrean/qrean.c | 39 +++++++------ src/Makefile | 14 ----- src/detector.c | 87 ++++++++++++++--------------- src/galois.h | 3 +- src/image.c | 98 ++++++++++++++++++++++----------- src/image.h | 35 +++++++++++- src/qrean.c | 5 ++ src/qrean.h | 2 + 10 files changed, 206 insertions(+), 137 deletions(-) diff --git a/Makefile b/Makefile index bc2b9ab..d012867 100644 --- a/Makefile +++ b/Makefile @@ -1,25 +1,38 @@ BUILDDIR?=$(abspath ./build/system) +#CFLAGS += -DUSE_MALLOC_BUFFER +#CFLAGS += -DNO_MALLOC +#CFLAGS += -DNO_PRINTF +#CFLAGS += -DNO_CALLBACK +#CFLAGS += -DNO_CANVAS_BUFFER + +#CFLAGS += -DNO_KANJI_TABLE + +#CFLAGS += -DNO_MQR +#CFLAGS += -DNO_RMQR + +#CFLAGS += -DNO_DEBUG + .PHONY: all clean examples cli wasm win32 mac all: cli cli: - @BUILDDIR=$(BUILDDIR) $(MAKE) -C cli + @BUILDDIR=$(BUILDDIR) CFLAGS="$(CFLAGS)" $(MAKE) -C cli install: cli - @BUILDDIR=$(BUILDDIR) $(MAKE) -C src install - @BUILDDIR=$(BUILDDIR) $(MAKE) -C cli install + @BUILDDIR=$(BUILDDIR) CFLAGS="$(CFLAGS)" $(MAKE) -C src install + @BUILDDIR=$(BUILDDIR) CFLAGS="$(CFLAGS)" $(MAKE) -C cli install clean: - @BUILDDIR=$(BUILDDIR) $(MAKE) -C cli clean + @BUILDDIR=$(BUILDDIR) CFLAGS="$(CFLAGS)" $(MAKE) -C cli clean -rmdir $(BUILDDIR) wasm: - @BUILDDIR=$(abspath ./build/wasm) NO_SHLIB=1 $(MAKE) -C wasm clean all + @BUILDDIR=$(abspath ./build/wasm) NO_SHLIB=1 CFLAGS="$(CFLAGS)" $(MAKE) -C wasm clean all win32: - @BUILDDIR=$(abspath ./build/win32) CC=i686-w64-mingw32-gcc AR=i686-w64-mingw32-ar NO_SHLIB=1 DLL=1 $(MAKE) clean cli + @BUILDDIR=$(abspath ./build/win32) CC=i686-w64-mingw32-gcc AR=i686-w64-mingw32-ar NO_SHLIB=1 DLL=1 CFLAGS="$(CFLAGS)" $(MAKE) clean cli mac: cli cp build/system/qrean build/system/qrean-detect ./dist/ @@ -29,4 +42,4 @@ dist: wasm win32 cp build/wasm/Qrean.* build/win32/*exe ./dist/ test: cli - @LD_LIBRARY_PATH=$(BUILDDIR) BUILDDIR=$(BUILDDIR) $(MAKE) -C tests + @LD_LIBRARY_PATH=$(BUILDDIR) BUILDDIR=$(BUILDDIR) CFLAGS="$(CFLAGS)" $(MAKE) -C tests diff --git a/cli/qrean-detect/qrean-detect.c b/cli/qrean-detect/qrean-detect.c index 656ae8a..c01cadf 100644 --- a/cli/qrean-detect/qrean-detect.c +++ b/cli/qrean-detect/qrean-detect.c @@ -19,7 +19,7 @@ #include "image.h" -image_t *img; +image_t image; image_t *detected; FILE *debug_out; @@ -113,15 +113,11 @@ static void on_found(qrean_detector_perspective_t *warp, void *opaque) fprintf(out, "%s\n", buffer); } -void decode(image_t* img) -{ -} - void done(pngle_t *pngle) { - image_t *mono = image_clone(img); + CREATE_IMAGE_BY_CLONE(mono, &image); - image_digitize(mono, img, gamma_value); + image_digitize(&mono, &image, gamma_value); // image_morphology_open(mono); // image_morphology_close(mono); @@ -132,23 +128,23 @@ void done(pngle_t *pngle) gettimeofday(&tv, NULL); for (int i = 0; i < n; i++) { int num_candidates; - qrean_detector_qr_finder_candidate_t *candidates = qrean_detector_scan_qr_finder_pattern(mono, &num_candidates); + qrean_detector_qr_finder_candidate_t *candidates = qrean_detector_scan_qr_finder_pattern(&mono, &num_candidates); if (flag_debug) { - // detected = image_clone(img); - detected = image_clone(mono); + // detected = image_clone(&image); + detected = image_clone(&mono); for (int i = 0; i < num_candidates; i++) { image_draw_filled_ellipse(detected, candidates[i].center, 5, 5, PIXEL(255, 0, 0)); image_draw_extent(detected, candidates[i].extent, PIXEL(255, 0, 0), 1); } } - found += qrean_detector_try_decode_qr(mono, candidates, num_candidates, on_found, NULL); - found += qrean_detector_try_decode_mqr(mono, candidates, num_candidates, on_found, NULL); - found += qrean_detector_try_decode_rmqr(mono, candidates, num_candidates, on_found, NULL); - found += qrean_detector_try_decode_tqr(mono, candidates, num_candidates, on_found, NULL); + found += qrean_detector_try_decode_qr(&mono, candidates, num_candidates, on_found, NULL); + found += qrean_detector_try_decode_mqr(&mono, candidates, num_candidates, on_found, NULL); + found += qrean_detector_try_decode_rmqr(&mono, candidates, num_candidates, on_found, NULL); + found += qrean_detector_try_decode_tqr(&mono, candidates, num_candidates, on_found, NULL); - found += qrean_detector_scan_barcodes(mono, on_found, NULL); + found += qrean_detector_scan_barcodes(&mono, on_found, NULL); } gettimeofday(&tv2, NULL); @@ -160,6 +156,8 @@ void done(pngle_t *pngle) fprintf(stderr, "Not found\n"); } if (debug_out) image_save_as_png(detected, debug_out); + + DESTROY_IMAGE(mono); } void draw_pixel(pngle_t *pngle, uint32_t x, uint32_t y, uint32_t w, uint32_t h, const uint8_t rgba[4]) @@ -168,14 +166,15 @@ void draw_pixel(pngle_t *pngle, uint32_t x, uint32_t y, uint32_t w, uint32_t h, uint8_t g = rgba[1]; uint8_t b = rgba[2]; - image_draw_pixel(img, POINT(x, y), PIXEL(r, g, b)); + image_draw_pixel(&image, POINT(x, y), PIXEL(r, g, b)); } void init_screen(pngle_t *pngle, uint32_t w, uint32_t h) { W = w; H = h; - img = new_image(W, H); + + image_init(&image, W, H, calloc(W * H, sizeof(image_pixel_t))); } const char *progname; diff --git a/cli/qrean/qrean.c b/cli/qrean/qrean.c index 7da3a64..7eccb53 100644 --- a/cli/qrean/qrean.c +++ b/cli/qrean/qrean.c @@ -302,49 +302,50 @@ int main(int argc, char *argv[]) return -1; } - qrean_t *qrean = new_qrean(code); - if (!qrean) { + qrean_t qrean = create_qrean(code); + if (!qrean_is_valid(&qrean)) { fprintf(stderr, "Unknown code or version; %d\n", code); return -1; } - qrean_set_bitmap_scale(qrean, scale); - if (padding) qrean_set_bitmap_padding(qrean, *padding); - if (QREAN_IS_TYPE_QRFAMILY(qrean)) { - qrean_set_qr_version(qrean, version); - qrean_set_qr_errorlevel(qrean, level); - qrean_set_qr_maskpattern(qrean, mask); + qrean_set_bitmap_scale(&qrean, scale); + if (padding) qrean_set_bitmap_padding(&qrean, *padding); + if (QREAN_IS_TYPE_QRFAMILY(&qrean)) { + qrean_set_qr_version(&qrean, version); + qrean_set_qr_errorlevel(&qrean, level); + qrean_set_qr_maskpattern(&qrean, mask); - if (!qrean_check_qr_combination(qrean)) { + if (!qrean_check_qr_combination(&qrean)) { fprintf(stderr, "Invalid combination of VERSION/LEVEL/MASK\n"); return -1; } - qrean_set_eci_code(qrean, eci_code); + qrean_set_eci_code(&qrean, eci_code); } if (save_as == SAVE_AS_DEFAULT) save_as = isatty(fileno(out)) ? SAVE_AS_TXT : SAVE_AS_PNG; - size_t wrote = qrean_write_buffer(qrean, data, len, data_type); + size_t wrote = qrean_write_buffer(&qrean, data, len, data_type); if (!wrote) { fprintf(stderr, "Size exceed or mismatch\n"); return -1; } - size_t width = qrean_get_bitmap_width(qrean); - size_t height = qrean_get_bitmap_height(qrean); + size_t width = qrean_get_bitmap_width(&qrean); + size_t height = qrean_get_bitmap_height(&qrean); size_t size = width * height * 4; - image_t *img = new_image(width, height); - qrean_read_bitmap(qrean, img->buffer, size, 32); + CREATE_IMAGE(img, width, height); + + qrean_read_bitmap(&qrean, img.buffer, size, 32); switch (save_as) { case SAVE_AS_PNG: - image_save_as_png(img, out); + image_save_as_png(&img, out); break; case SAVE_AS_PPM: - image_save_as_ppm(img, out); + image_save_as_ppm(&img, out); break; default: @@ -353,12 +354,14 @@ int main(int argc, char *argv[]) unsigned int cp = GetConsoleOutputCP(); SetConsoleOutputCP(65001); #endif - qrean_dump(qrean, out); + qrean_dump(&qrean, out); #ifdef __WIN32 SetConsoleOutputCP(cp); #endif break; } + DESTROY_IMAGE(img); + return 0; } diff --git a/src/Makefile b/src/Makefile index 7a68780..fe7b4a9 100644 --- a/src/Makefile +++ b/src/Makefile @@ -29,7 +29,6 @@ SRCS += code_code93.c SRCS += code_itf.c SRCS += code_nw7.c -## Works only without NO_MALLOC SRCS += image.c SRCS += detector.c @@ -45,19 +44,6 @@ CFLAGS += -Wall # -Werror CFLAGS += -Wno-misleading-indentation CFLAGS += -fPIC -#CFLAGS += -D USE_MALLOC_BUFFER -#CFLAGS += -D NO_MALLOC -#CFLAGS += -D NO_PRINTF -#CFLAGS += -D NO_CALLBACK -#CFLAGS += -D NO_CANVAS_BUFFER - -#CFLAGS += -D NO_KANJI_TABLE - -#CFLAGS += -D NO_MQR -#CFLAGS += -D NO_RMQR - -#CFLAGS += -D NO_DEBUG - LDFLAGS += -lm ifndef NO_DEBUG CFLAGS += -g diff --git a/src/detector.c b/src/detector.c index e47b86a..dc49237 100644 --- a/src/detector.c +++ b/src/detector.c @@ -168,34 +168,34 @@ int qrean_detector_scan_barcodes(image_t *src, void (*on_found)(qrean_detector_p { int step = 10; // XXX: reduce CPU time... int found = 0; - image_t *img = image_clone(src); - if (!img) return 0; + + CREATE_IMAGE_BY_CLONE(work, src); runlength_t rl = create_runlength(); - for (int y = 0; y < (int)img->height; y += step) { + for (int y = 0; y < (int)work.height; y += step) { runlength_init(&rl); - for (int x = 0; x < (int)img->width; x++) { - scan_barcode(&rl, img, src, x, y, 1, 0, on_found, opaque); + for (int x = 0; x < (int)work.width; x++) { + scan_barcode(&rl, &work, src, x, y, 1, 0, on_found, opaque); } runlength_init(&rl); - for (int x = 0; x < (int)img->width; x++) { - scan_barcode(&rl, img, src, img->width - 1 - x, y, -1, 0, on_found, opaque); + for (int x = 0; x < (int)work.width; x++) { + scan_barcode(&rl, &work, src, work.width - 1 - x, y, -1, 0, on_found, opaque); } } - for (int x = 0; x < (int)img->width; x += step) { + for (int x = 0; x < (int)work.width; x += step) { runlength_init(&rl); - for (int y = 0; y < (int)img->height; y++) { - scan_barcode(&rl, img, src, x, y, 0, 1, on_found, opaque); + for (int y = 0; y < (int)work.height; y++) { + scan_barcode(&rl, &work, src, x, y, 0, 1, on_found, opaque); } runlength_init(&rl); - for (int y = 0; y < (int)img->height; y++) { - scan_barcode(&rl, img, src, x, img->height - 1 - y, 0, -1, on_found, opaque); + for (int y = 0; y < (int)work.height; y++) { + scan_barcode(&rl, &work, src, x, work.height - 1 - y, 0, -1, on_found, opaque); } } - image_free(img); + DESTROY_IMAGE(work); return found; } @@ -205,14 +205,13 @@ qrean_detector_qr_finder_candidate_t *qrean_detector_scan_qr_finder_pattern(imag static qrean_detector_qr_finder_candidate_t candidates[MAX_CANDIDATES]; int candidx = 0; - image_t *img = image_clone(src); - if (!img) return NULL; + CREATE_IMAGE_BY_CLONE(img, src); - for (int y = 0; y < (int)img->height; y++) { + for (int y = 0; y < (int)img.height; y++) { runlength_t rl = create_runlength(); - for (int x = 0; x < (int)img->width; x++) { - uint32_t v = image_read_pixel(img, POINT(x, y)); + for (int x = 0; x < (int)img.width; x++) { + uint32_t v = image_read_pixel(&img, POINT(x, y)); if (v != 0 && v != PIXEL(255, 255, 255)) { runlength_init(&rl); continue; @@ -231,21 +230,21 @@ qrean_detector_qr_finder_candidate_t *qrean_detector_scan_qr_finder_pattern(imag int cy = y; // not a dark module - if (image_read_pixel(img, POINT(cx, cy)) != 0) continue; - if (image_read_pixel(img, POINT(lx, cy)) != 0) continue; - if (image_read_pixel(img, POINT(rx, cy)) != 0) continue; + if (image_read_pixel(&img, POINT(cx, cy)) != 0) continue; + if (image_read_pixel(&img, POINT(lx, cy)) != 0) continue; + if (image_read_pixel(&img, POINT(rx, cy)) != 0) continue; // check vertical runlength runlength_t rlvu = create_runlength(); runlength_t rlvd = create_runlength(); int found_u = 0, found_d = 0; for (int yy = 0; yy < len; yy++) { - if (!found_u && runlength_push_value(&rlvu, image_read_pixel(img, POINT(cx, cy - yy)))) { + if (!found_u && runlength_push_value(&rlvu, image_read_pixel(&img, POINT(cx, cy - yy)))) { if (runlength_match_ratio(&rlvu, 3, 2, 2, 0, -1)) { found_u = runlength_sum(&rlvu, 1, 3); } } - if (!found_d && runlength_push_value(&rlvd, image_read_pixel(img, POINT(cx, cy + yy)))) { + if (!found_d && runlength_push_value(&rlvd, image_read_pixel(&img, POINT(cx, cy + yy)))) { if (runlength_match_ratio(&rlvd, 3, 2, 2, 0, -1)) { found_d = runlength_sum(&rlvd, 1, 3); } @@ -263,27 +262,27 @@ qrean_detector_qr_finder_candidate_t *qrean_detector_scan_qr_finder_pattern(imag image_pixel_t ring_color = PIXEL(255, 0, 0); // mark visit flag by painting inner most block - image_paint_result_t inner_block = image_paint(img, POINT(cx, cy), inner_block_color); + image_paint_result_t inner_block = image_paint(&img, POINT(cx, cy), inner_block_color); // let's make sure they are disconnected from the inner most block - if (image_read_pixel(img, POINT(lx, cy)) != PIXEL(0, 0, 0)) { + if (image_read_pixel(&img, POINT(lx, cy)) != PIXEL(0, 0, 0)) { continue; } - if (image_read_pixel(img, POINT(rx, cy)) != PIXEL(0, 0, 0)) { + if (image_read_pixel(&img, POINT(rx, cy)) != PIXEL(0, 0, 0)) { continue; } // let's make sure they are connected - image_paint_result_t ring = image_paint(img, POINT(lx, cy), ring_color); - if (image_read_pixel(img, POINT(lx, cy)) != image_read_pixel(img, POINT(rx, cy))) { + image_paint_result_t ring = image_paint(&img, POINT(lx, cy), ring_color); + if (image_read_pixel(&img, POINT(lx, cy)) != image_read_pixel(&img, POINT(rx, cy))) { // paint it back ;) - image_paint(img, POINT(lx, cy), PIXEL(0, 0, 0)); + image_paint(&img, POINT(lx, cy), PIXEL(0, 0, 0)); continue; } float real_cx = (ring.extent.left + ring.extent.right) / 2.0f; float real_cy = (ring.extent.top + ring.extent.bottom) / 2.0f; - if (image_read_pixel(img, POINT(real_cx, real_cy)) != inner_block_color) continue; + if (image_read_pixel(&img, POINT(real_cx, real_cy)) != inner_block_color) continue; // find ring corners int w = ring.extent.right - ring.extent.left; @@ -296,7 +295,7 @@ qrean_detector_qr_finder_candidate_t *qrean_detector_scan_qr_finder_pattern(imag float x = floor(cx + r * sin(theta)); float y = floor(cy - r * cos(theta)); - if (image_read_pixel(img, POINT(x, y)) == ring_color) { + if (image_read_pixel(&img, POINT(x, y)) == ring_color) { int slot = !cidx ? 0 : floor(fmod(theta + 2 * M_PI + M_PI_4 - corners[0], 2 * M_PI) / M_PI_2); assert(0 <= slot && slot < 4); @@ -311,7 +310,7 @@ qrean_detector_qr_finder_candidate_t *qrean_detector_scan_qr_finder_pattern(imag if (cidx < 4) { // No corners... paint it back - image_paint(img, POINT(lx, cy), PIXEL(0, 0, 0)); + image_paint(&img, POINT(lx, cy), PIXEL(0, 0, 0)); continue; } @@ -323,7 +322,7 @@ qrean_detector_qr_finder_candidate_t *qrean_detector_scan_qr_finder_pattern(imag } } - image_free(img); + DESTROY_IMAGE(img); // guardian candidates[candidx].center = POINT(NAN, NAN); @@ -387,8 +386,8 @@ void qrean_detector_perspective_setup_by_qr_finder_pattern_ring_corners( int qrean_detector_perspective_fit_for_qr(qrean_detector_perspective_t *warp) { - image_t *img = image_clone(warp->img); - // image_t *img = warp->img; + CREATE_IMAGE_BY_CLONE(img, warp->img); + int adjusted = 0; int N = qrspec_get_alignment_num(warp->qrean->qr.version); @@ -406,8 +405,8 @@ int qrean_detector_perspective_fit_for_qr(qrean_detector_perspective_t *warp) for (float x = cx - dist; x < cx + dist; x += 0.2) { image_point_t p = image_point_transform(POINT(x, y), warp->h); image_point_t ring = image_point_transform(POINT(x + 1, y), warp->h); - if (image_read_pixel(img, p) == 0 && image_read_pixel(img, ring) == PIXEL(255, 255, 255)) { - image_paint_result_t result = image_paint(img, ring, PIXEL(255, 0, 0)); + if (image_read_pixel(&img, p) == 0 && image_read_pixel(&img, ring) == PIXEL(255, 255, 255)) { + image_paint_result_t result = image_paint(&img, ring, PIXEL(255, 0, 0)); if (module_size * module_size < result.area && result.area < module_size * module_size * 16) { image_point_t new_center = image_extent_center(&result.extent); @@ -418,7 +417,7 @@ int qrean_detector_perspective_fit_for_qr(qrean_detector_perspective_t *warp) warp->h = create_image_transform_matrix(warp->src, warp->dst); if (qrean_read_qr_alignment_pattern(warp->qrean, i) < 10) { - image_paint(img, ring, PIXEL(0, 255, 0)); + image_paint(&img, ring, PIXEL(0, 255, 0)); adjusted = 1; goto next; @@ -433,7 +432,7 @@ int qrean_detector_perspective_fit_for_qr(qrean_detector_perspective_t *warp) next:; } - image_free(img); + DESTROY_IMAGE(img); return adjusted; } @@ -573,12 +572,14 @@ static image_point_t find_rmqr_corner_finder_pattern( if (image_read_pixel(warp->img, p) != 0) continue; if (found < n) { - image_t *work = image_clone(warp->img); - image_paint_result_t painted = image_paint(work, p, PIXEL(255, 0, 0)); + CREATE_IMAGE_BY_CLONE(work, warp->img); + + image_paint_result_t painted = image_paint(&work, p, PIXEL(255, 0, 0)); image_point_t c = image_extent_center(&painted.extent); float dist = image_point_distance(c, p) * 1.2; - p = find_corner(work, c, PIXEL(255, 0, 0), dist, image_point_angle(c, p), modsize * 1.5 / dist); - image_free(work); + p = find_corner(&work, c, PIXEL(255, 0, 0), dist, image_point_angle(c, p), modsize * 1.5 / dist); + + DESTROY_IMAGE(work); found = n; last_p = p; diff --git a/src/galois.h b/src/galois.h index dd72d15..2e0aa9a 100644 --- a/src/galois.h +++ b/src/galois.h @@ -15,8 +15,7 @@ typedef uint8_t gf2_value_t; #define GF2_POLY_COEFF(x, i) ((x)[1 + (i)]) // #define GF2_POLY_COEFF(x, i) ((x)[1 + GF2_POLY_DEGREE(x) - (i)]) #define CREATE_GF2_POLY(name, degree) \ - gf2_value_t name[GF2_POLY_SIZE((degree))]; \ - memset(name, 0, sizeof(name)); \ + gf2_value_t name[GF2_POLY_SIZE((degree))] = {}; \ GF2_POLY_DEGREE(name) = (degree); typedef gf2_value_t gf2_poly_t; diff --git a/src/image.c b/src/image.c index 0899a84..7bdaae1 100644 --- a/src/image.c +++ b/src/image.c @@ -13,46 +13,78 @@ // #define RINT(x) (x) #define RINT(x) round(x) +void image_init(image_t *img, size_t width, size_t height, void *buffer) +{ + img->width = width; + img->height = height; + img->buffer = buffer; +} + +image_pixel_t *new_image_buffer(size_t width, size_t height) +{ +#ifndef NO_MALLOC + return (image_pixel_t *)calloc(width * height, sizeof(image_pixel_t)); +#else + return NULL; +#endif +} + +void image_buffer_free(image_pixel_t *buffer) +{ +#ifndef NO_MALLOC + free(buffer); +#endif +} + image_t *new_image(size_t width, size_t height) { +#ifndef NO_MALLOC image_t *img = (image_t *)malloc(sizeof(image_t)); if (!img) return NULL; - img->width = width; - img->height = height; - img->buffer = (image_pixel_t *)calloc(width * height, sizeof(image_pixel_t)); - if (!img->buffer) { + void *buffer = new_image_buffer(width, height); + if (!buffer) { free(img); return NULL; } + image_init(img, width, height, buffer); return img; +#else + return NULL; +#endif } void image_free(image_t *img) { - free(img->buffer); +#ifndef NO_MALLOC + image_buffer_free(img->buffer); free(img); +#endif } -image_t *image_clone(image_t *img) +image_t create_image(size_t width, size_t height, void *buffer) { - image_t *clone = new_image(img->width, img->height); - if (clone) { - memcpy(clone->buffer, img->buffer, img->width * img->height * sizeof(image_pixel_t)); - } - return clone; + image_t img = {}; + image_init(&img, width, height, buffer); + return img; } -image_t *new_image_from_qrean(qrean_t *qrean) +image_t *image_copy(image_t *dst, image_t *src) { - size_t width = qrean_get_bitmap_width(qrean); - size_t height = qrean_get_bitmap_height(qrean); - image_t *img = new_image(width, height); - if (img) { - qrean_read_bitmap(qrean, img->buffer, width * height * sizeof(img->buffer[0]), sizeof(img->buffer[0]) * 8); - } - return img; + memcpy(dst->buffer, src->buffer, src->width * src->height * sizeof(image_pixel_t)); + return dst; +} + +image_t *image_clone(image_t *img) +{ +#ifndef NO_MALLOC + image_t *clone = new_image(img->width, img->height); + if (clone) image_copy(clone, img); + return clone; +#else + return NULL; +#endif } image_point_t create_image_point(float x, float y) @@ -467,17 +499,17 @@ image_transform_matrix_t create_image_transform_matrix(image_point_t src[4], ima void image_morphology_erode(image_t *dst) { - image_t *src = image_clone(dst); - for (int y = 0; y < (int)src->height; y++) { - for (int x = 0; x < (int)src->width; x++) { - image_pixel_t pix = image_read_pixel(src, POINT(x, y)); + CREATE_IMAGE_BY_CLONE(src, dst); + for (int y = 0; y < (int)src.height; y++) { + for (int x = 0; x < (int)src.width; x++) { + image_pixel_t pix = image_read_pixel(&src, POINT(x, y)); if (pix == 0) continue; for (int dy = -1; dy <= 1; dy++) { for (int dx = -1; dx <= 1; dx++) { if (dx == 0 && dy == 0) continue; - if (x + dx < 0 || y + dy < 0 || x + dx >= (int)src->width || y + dy >= (int)src->height) continue; - if (image_read_pixel(src, POINT(x + dx, y + dy)) == 0) { + if (x + dx < 0 || y + dy < 0 || x + dx >= (int)src.width || y + dy >= (int)src.height) continue; + if (image_read_pixel(&src, POINT(x + dx, y + dy)) == 0) { image_draw_pixel(dst, POINT(x, y), 0); goto next; } @@ -486,22 +518,22 @@ void image_morphology_erode(image_t *dst) next:; } } - image_free(src); + DESTROY_IMAGE(src); } void image_morphology_dilate(image_t *dst) { - image_t *src = image_clone(dst); - for (int y = 0; y < (int)src->height; y++) { - for (int x = 0; x < (int)src->width; x++) { - image_pixel_t pix = image_read_pixel(src, POINT(x, y)); + CREATE_IMAGE_BY_CLONE(src, dst); + for (int y = 0; y < (int)src.height; y++) { + for (int x = 0; x < (int)src.width; x++) { + image_pixel_t pix = image_read_pixel(&src, POINT(x, y)); if (pix != 0) continue; for (int dy = -1; dy <= 1; dy++) { for (int dx = -1; dx <= 1; dx++) { if (dx == 0 && dy == 0) continue; - if (x + dx < 0 || y + dy < 0 || x + dx >= (int)src->width || y + dy >= (int)src->height) continue; - if (image_read_pixel(src, POINT(x + dx, y + dy)) != 0) { + if (x + dx < 0 || y + dy < 0 || x + dx >= (int)src.width || y + dy >= (int)src.height) continue; + if (image_read_pixel(&src, POINT(x + dx, y + dy)) != 0) { image_draw_pixel(dst, POINT(x, y), PIXEL(255, 255, 255)); goto next; } @@ -510,7 +542,7 @@ void image_morphology_dilate(image_t *dst) next:; } } - image_free(src); + DESTROY_IMAGE(src); } void image_morphology_close(image_t *dst) diff --git a/src/image.h b/src/image.h index 67f6887..b53e335 100644 --- a/src/image.h +++ b/src/image.h @@ -4,6 +4,7 @@ #include "qrean.h" #include #include +#include typedef uint32_t image_pixel_t; #define PIXEL(r, g, b) ((((uint32_t)(r)) << 0) | ((g) << 8) | ((b) << 16)) @@ -12,10 +13,10 @@ typedef uint32_t image_pixel_t; #define PIXEL_GET_B(pix) (((pix) >> 16) & 0xFF) typedef struct { - image_pixel_t *buffer; - size_t width; size_t height; + + image_pixel_t *buffer; } image_t; typedef struct { @@ -39,10 +40,38 @@ typedef struct { float m[8]; } image_transform_matrix_t; +image_t create_image(size_t width, size_t height, void *buffer); +image_t *image_copy(image_t *dst, image_t *src); + +// malloc version image_t *new_image(size_t width, size_t height); void image_free(image_t *img); image_t *image_clone(image_t *img); -image_t *new_image_from_qrean(qrean_t *qrean); +image_pixel_t *new_image_buffer(size_t width, size_t height); +void image_buffer_free(image_pixel_t *buffer); + +// internal +void image_init(image_t *img, size_t width, size_t height, void *buffer); + +#ifdef NO_MALLOC +// stack version +#define CREATE_IMAGE(name, width, height) \ + image_pixel_t _##name##__buffer[(width) * (height)] = {}; \ + image_t name = create_image((width), (height), _##name##__buffer); + +#define DESTROY_IMAGE(name) (void)(name); +#else +// malloc version +#define CREATE_IMAGE(name, width, height) \ + image_pixel_t *_##name##__buffer = new_image_buffer(width, height); \ + image_t name = create_image((width), (height), _##name##__buffer); + +#define DESTROY_IMAGE(name) image_buffer_free(_##name##__buffer); +#endif +#define CREATE_IMAGE_BY_CLONE(name, src) \ + CREATE_IMAGE(name, (src)->width, (src)->height); \ + image_copy(&name, src); + // image_point_t typedef struct { diff --git a/src/qrean.c b/src/qrean.c index afb8353..f9eb4a6 100644 --- a/src/qrean.c +++ b/src/qrean.c @@ -98,6 +98,11 @@ void qrean_free(qrean_t *qrean) #endif } +bit_t qrean_is_valid(qrean_t *qrean) +{ + return qrean && qrean->code ? 1 : 0; +} + bit_t qrean_set_qr_version(qrean_t *qrean, qr_version_t version) { if (!QREAN_IS_TYPE_QRFAMILY(qrean)) return 0; diff --git a/src/qrean.h b/src/qrean.h index 59ddd1e..0941747 100644 --- a/src/qrean.h +++ b/src/qrean.h @@ -137,6 +137,8 @@ void qrean_destroy(qrean_t *qrean); qrean_t *new_qrean(qrean_code_type_t type); void qrean_free(qrean_t *qrean); +bit_t qrean_is_valid(qrean_t *qrean); + // ========= code operation (QR) bit_t qrean_set_qr_version(qrean_t *qrean, qr_version_t version); bit_t qrean_set_qr_errorlevel(qrean_t *qrean, qr_errorlevel_t level);