From 964da5ac7e60aaf08c03c38c5d6be5c01a8959be Mon Sep 17 00:00:00 2001 From: axxel Date: Tue, 5 Mar 2024 11:21:32 +0100 Subject: [PATCH] c-API: add support for experimental writer API --- core/src/ZXingC.cpp | 116 ++++++++++++++++++++++++++++++++++++++++ core/src/ZXingC.h | 70 +++++++++++++++++++++++- wrappers/c/ZXingCTest.c | 82 +++++++++++++++++----------- 3 files changed, 236 insertions(+), 32 deletions(-) diff --git a/core/src/ZXingC.cpp b/core/src/ZXingC.cpp index 4bef66b674..b89bd5541e 100644 --- a/core/src/ZXingC.cpp +++ b/core/src/ZXingC.cpp @@ -112,6 +112,31 @@ void ZXing_ImageView_rotate(ZXing_ImageView* iv, int degree) *iv = iv->rotated(degree); } +void ZXing_Image_delete(ZXing_Image* img) +{ + delete img; +} + +const uint8_t* ZXing_Image_data(const ZXing_Image* img) +{ + return img->data(); +} + +int ZXing_Image_width(const ZXing_Image* img) +{ + return img->width(); +} + +int ZXing_Image_height(const ZXing_Image* img) +{ + return img->height(); +} + +ZXing_ImageFormat ZXing_Image_format(const ZXing_Image* img) +{ + return static_cast(img->format()); +} + /* * ZXing/BarcodeFormat.h */ @@ -288,6 +313,97 @@ ZXing_Barcode* ZXing_Barcodes_move(ZXing_Barcodes* barcodes, int i) ZX_TRY(new Barcode(std::move((*barcodes)[i]))); } +#ifdef ZXING_BUILD_EXPERIMENTAL_API +/* + * ZXing/WriteBarcode.h + */ + +ZXing_CreatorOptions* ZXing_CreatorOptions_new(ZXing_BarcodeFormat format) +{ + ZX_TRY(new CreatorOptions(static_cast(format))); +} + +void ZXing_CreatorOptions_delete(ZXing_CreatorOptions* opts) +{ + delete opts; +} + +#define ZX_PROPERTY(TYPE, GETTER, SETTER) \ + TYPE ZXing_CreatorOptions_get##SETTER(const ZXing_CreatorOptions* opts) { return opts->GETTER(); } \ + void ZXing_CreatorOptions_set##SETTER(ZXing_CreatorOptions* opts, TYPE val) { opts->GETTER(val); } + +ZX_PROPERTY(bool, readerInit, ReaderInit) +ZX_PROPERTY(bool, forceSquareDataMatrix, ForceSquareDataMatrix) + +#undef ZX_PROPERTY + +//ZX_PROPERTY(BarcodeFormat, format, Format) + +char* ZXing_CreatorOptions_getEcLevel(const ZXing_CreatorOptions* opts) +{ + return copy(opts->ecLevel()); +} + +void ZXing_CreatorOptions_setEcLevel(ZXing_CreatorOptions* opts, const char* val) +{ + opts->ecLevel(val); +} + + +ZXing_WriterOptions* ZXing_WriterOptions_new() +{ + ZX_TRY(new ZXing_WriterOptions()); +} + +void ZXing_WriterOptions_delete(ZXing_CreatorOptions* opts) +{ + delete opts; +} + +#define ZX_PROPERTY(TYPE, GETTER, SETTER) \ + TYPE ZXing_WriterOptions_get##SETTER(const ZXing_WriterOptions* opts) { return opts->GETTER(); } \ + void ZXing_WriterOptions_set##SETTER(ZXing_WriterOptions* opts, TYPE val) { opts->GETTER(val); } + +ZX_PROPERTY(int, scale, Scale) +ZX_PROPERTY(int, sizeHint, SizeHint) +ZX_PROPERTY(int, rotate, Rotate) +ZX_PROPERTY(bool, withHRT, WithHRT) +ZX_PROPERTY(bool, withQuietZones, WithQuietZones) + +#undef ZX_PROPERTY + +ZXing_Barcode* ZXing_CreateBarcodeFromText(const char* data, int size, const ZXing_CreatorOptions* opts) +{ + ZX_CHECK(data && opts, "Data and/or options param in CreateBarcodeFromText is NULL") + ZX_TRY(new Barcode(CreateBarcodeFromText({data, size ? static_cast(size) : strlen(data)}, *opts));) +} + +ZXing_Barcode* ZXing_CreateBarcodeFromBytes(const void* data, int size, const ZXing_CreatorOptions* opts) +{ + ZX_CHECK(data && size && opts, "Data and/or options param in CreateBarcodeFromBytes is NULL") + ZX_TRY(new Barcode(CreateBarcodeFromBytes(data, size, *opts))) +} + +char* ZXing_WriteBarcodeToSVG(const ZXing_Barcode* barcode, const ZXing_WriterOptions* opts) +{ + static WriterOptions defOpts; + ZX_CHECK(barcode, "Barcode param in WriteBarcodeToSVG is NULL") + ZX_TRY(copy(WriteBarcodeToSVG(*barcode, *(opts ? opts : &defOpts)))) +} + +ZXing_Image* ZXing_WriteBarcodeToImage(const ZXing_Barcode* barcode, const ZXing_WriterOptions* opts) +{ + static WriterOptions defOpts; + ZX_CHECK(barcode, "Barcode param in WriteBarcodeToSVG is NULL") + ZX_TRY(new Image(WriteBarcodeToImage(*barcode, *(opts ? opts : &defOpts)))) +} + +#endif + +/* + * ZXingC.h + */ + char* ZXing_LastErrorMsg() { if (lastErrorMsg.empty()) diff --git a/core/src/ZXingC.h b/core/src/ZXingC.h index 309ac15dd8..1e67b7e0bb 100644 --- a/core/src/ZXingC.h +++ b/core/src/ZXingC.h @@ -12,11 +12,20 @@ #ifdef __cplusplus -#include "ReaderOptions.h" -#include "ImageView.h" #include "Barcode.h" +#include "ImageView.h" +#include "ReaderOptions.h" +#include "WriteBarcode.h" typedef ZXing::ImageView ZXing_ImageView; +typedef ZXing::Image ZXing_Image; +#ifdef ZXING_BUILD_EXPERIMENTAL_API +typedef ZXing::CreatorOptions ZXing_CreatorOptions; +typedef ZXing::WriterOptions ZXing_WriterOptions; +#else +typedef struct ZXing_CreatorOptions ZXing_CreatorOptions; +typedef struct ZXing_WriterOptions ZXing_WriterOptions; +#endif typedef ZXing::ReaderOptions ZXing_ReaderOptions; typedef ZXing::Barcode ZXing_Barcode; typedef ZXing::Barcodes ZXing_Barcodes; @@ -26,7 +35,10 @@ extern "C" #else typedef struct ZXing_ImageView ZXing_ImageView; +typedef struct ZXing_Image ZXing_Image; typedef struct ZXing_ReaderOptions ZXing_ReaderOptions; +typedef struct ZXing_CreatorOptions ZXing_CreatorOptions; +typedef struct ZXing_WriterOptions ZXing_WriterOptions; typedef struct ZXing_Barcode ZXing_Barcode; typedef struct ZXing_Barcodes ZXing_Barcodes; @@ -57,6 +69,13 @@ void ZXing_ImageView_delete(ZXing_ImageView* iv); void ZXing_ImageView_crop(ZXing_ImageView* iv, int left, int top, int width, int height); void ZXing_ImageView_rotate(ZXing_ImageView* iv, int degree); +void ZXing_Image_delete(ZXing_Image* img); + +const uint8_t* ZXing_Image_data(const ZXing_Image* img); +int ZXing_Image_width(const ZXing_Image* img); +int ZXing_Image_height(const ZXing_Image* img); +ZXing_ImageFormat ZXing_Image_format(const ZXing_Image* img); + /* * ZXing/BarcodeFormat.h */ @@ -232,6 +251,53 @@ char* ZXing_LastErrorMsg(); void ZXing_free(void* ptr); +/* + * ZXing/WriteBarcode.h + */ + +ZXing_CreatorOptions* ZXing_CreatorOptions_new(ZXing_BarcodeFormat format); +void ZXing_CreatorOptions_delete(ZXing_CreatorOptions* opts); + +void ZXing_CreatorOptions_setFormat(ZXing_CreatorOptions* opts, ZXing_BarcodeFormat format); +ZXing_BarcodeFormat ZXing_CreatorOptions_getFormat(const ZXing_CreatorOptions* opts); + +void ZXing_CreatorOptions_setReaderInit(ZXing_CreatorOptions* opts, bool readerInit); +bool ZXing_CreatorOptions_getReaderInit(const ZXing_CreatorOptions* opts); + +void ZXing_CreatorOptions_setForceSquareDataMatrix(ZXing_CreatorOptions* opts, bool forceSquareDataMatrix); +bool ZXing_CreatorOptions_getForceSquareDataMatrix(const ZXing_CreatorOptions* opts); + +void ZXing_CreatorOptions_setEcLevel(ZXing_CreatorOptions* opts, const char* ecLevel); +char* ZXing_CreatorOptions_getEcLevel(const ZXing_CreatorOptions* opts); + + +ZXing_WriterOptions* ZXing_WriterOptions_new(); +void ZXing_WriterOptions_delete(ZXing_CreatorOptions* opts); + +void ZXing_WriterOptions_setScale(ZXing_WriterOptions* opts, int scale); +int ZXing_WriterOptions_getScale(const ZXing_WriterOptions* opts); + +void ZXing_WriterOptions_setSizeHint(ZXing_WriterOptions* opts, int sizeHint); +int ZXing_WriterOptions_getSizeHint(const ZXing_WriterOptions* opts); + +void ZXing_WriterOptions_setRotate(ZXing_WriterOptions* opts, int rotate); +int ZXing_WriterOptions_getRotate(const ZXing_WriterOptions* opts); + +void ZXing_WriterOptions_setWithHRT(ZXing_WriterOptions* opts, bool withHRT); +bool ZXing_WriterOptions_getWithHRT(const ZXing_WriterOptions* opts); + +void ZXing_WriterOptions_setWithQuietZones(ZXing_WriterOptions* opts, bool withQuietZones); +bool ZXing_WriterOptions_getWithQuietZones(const ZXing_WriterOptions* opts); + + +ZXing_Barcode* ZXing_CreateBarcodeFromText(const char* data, int size, const ZXing_CreatorOptions* opts); +ZXing_Barcode* ZXing_CreateBarcodeFromBytes(const void* data, int size, const ZXing_CreatorOptions* opts); + +/** Note: opts is optional, i.e. it can be NULL, which will imply default settings. */ +char* ZXing_WriteBarcodeToSVG(const ZXing_Barcode* barcode, const ZXing_WriterOptions* opts); +ZXing_Image* ZXing_WriteBarcodeToImage(const ZXing_Barcode* barcode, const ZXing_WriterOptions* opts); + + #ifdef __cplusplus } #endif diff --git a/wrappers/c/ZXingCTest.c b/wrappers/c/ZXingCTest.c index fbac6edd1d..6685dd9b31 100644 --- a/wrappers/c/ZXingCTest.c +++ b/wrappers/c/ZXingCTest.c @@ -44,6 +44,14 @@ void printF(const char* fmt, char* text) ZXing_free(text); } +#define CHECK(GOOD) \ + if (!(GOOD)) { \ + char* error = ZXing_LastErrorMsg(); \ + fprintf(stderr, "CHECK(%s) failed: %s\n", #GOOD, error); \ + ZXing_free(error); \ + return 2; \ + } + int main(int argc, char** argv) { int ret = 0; @@ -57,9 +65,30 @@ int main(int argc, char** argv) int height = 0; int channels = 0; stbi_uc* data = stbi_load(filename, &width, &height, &channels, STBI_grey); - if (!data) { + + ZXing_ImageView* iv = NULL; + ZXing_Image* img = NULL; + + if (data) { + iv = ZXing_ImageView_new(data, width, height, ZXing_ImageFormat_Lum, 0, 0); + CHECK(iv) + } else { fprintf(stderr, "Could not read image '%s'\n", filename); +#ifdef ZXING_BUILD_EXPERIMENTAL_API + if (formats == ZXing_BarcodeFormat_Invalid) + return 2; + fprintf(stderr, "Using '%s' as text input to create barcode\n", filename); + ZXing_CreatorOptions* cOpts = ZXing_CreatorOptions_new(formats); + CHECK(cOpts) + ZXing_Barcode* barcode = ZXing_CreateBarcodeFromText(filename, 0, cOpts); + CHECK(barcode) + img = ZXing_WriteBarcodeToImage(barcode, NULL); + CHECK(img) + ZXing_CreatorOptions_delete(cOpts); + ZXing_Barcode_delete(barcode); +#else return 2; +#endif } ZXing_ReaderOptions* opts = ZXing_ReaderOptions_new(); @@ -68,42 +97,35 @@ int main(int argc, char** argv) ZXing_ReaderOptions_setFormats(opts, formats); ZXing_ReaderOptions_setReturnErrors(opts, true); - ZXing_ImageView* iv = ZXing_ImageView_new(data, width, height, ZXing_ImageFormat_Lum, 0, 0); - - ZXing_Barcodes* barcodes = ZXing_ReadBarcodes(iv, opts); + ZXing_Barcodes* barcodes = ZXing_ReadBarcodes(iv ? iv : (ZXing_ImageView*)img, opts); + CHECK(barcodes) ZXing_ImageView_delete(iv); + ZXing_Image_delete(img); ZXing_ReaderOptions_delete(opts); stbi_image_free(data); - if (barcodes) { - for (int i = 0, n = ZXing_Barcodes_size(barcodes); i < n; ++i) { - const ZXing_Barcode* barcode = ZXing_Barcodes_at(barcodes, i); - - printF("Text : %s\n", ZXing_Barcode_text(barcode)); - printF("BytesECI : %s\n", (char*)ZXing_Barcode_bytesECI(barcode, NULL)); - printF("Format : %s\n", ZXing_BarcodeFormatToString(ZXing_Barcode_format(barcode))); - printF("Content : %s\n", ZXing_ContentTypeToString(ZXing_Barcode_contentType(barcode))); - printF("Identifier : %s\n", ZXing_Barcode_symbologyIdentifier(barcode)); - printF("EC Level : %s\n", ZXing_Barcode_ecLevel(barcode)); - printF("Error : %s\n", ZXing_Barcode_errorMsg(barcode)); - printF("Position : %s\n", ZXing_PositionToString(ZXing_Barcode_position(barcode))); - printf("Rotation : %d\n", ZXing_Barcode_orientation(barcode)); - - if (i < n-1) - printf("\n"); - } + for (int i = 0, n = ZXing_Barcodes_size(barcodes); i < n; ++i) { + const ZXing_Barcode* barcode = ZXing_Barcodes_at(barcodes, i); + + printF("Text : %s\n", ZXing_Barcode_text(barcode)); + printF("BytesECI : %s\n", (char*)ZXing_Barcode_bytesECI(barcode, NULL)); + printF("Format : %s\n", ZXing_BarcodeFormatToString(ZXing_Barcode_format(barcode))); + printF("Content : %s\n", ZXing_ContentTypeToString(ZXing_Barcode_contentType(barcode))); + printF("Identifier : %s\n", ZXing_Barcode_symbologyIdentifier(barcode)); + printF("EC Level : %s\n", ZXing_Barcode_ecLevel(barcode)); + printF("Error : %s\n", ZXing_Barcode_errorMsg(barcode)); + printF("Position : %s\n", ZXing_PositionToString(ZXing_Barcode_position(barcode))); + printf("Rotation : %d\n", ZXing_Barcode_orientation(barcode)); + + if (i < n-1) + printf("\n"); + } - if (ZXing_Barcodes_size(barcodes) == 0) - printf("No barcode found\n"); + if (ZXing_Barcodes_size(barcodes) == 0) + printf("No barcode found\n"); - ZXing_Barcodes_delete(barcodes); - } else { - char* error = ZXing_LastErrorMsg(); - fprintf(stderr, "%s\n", error); - ZXing_free(error); - ret = 2; - } + ZXing_Barcodes_delete(barcodes); return ret; }