diff --git a/.github/workflows/run-tests-ci.yml b/.github/workflows/run-tests-ci.yml index 9ddd06a..39eb4ce 100644 --- a/.github/workflows/run-tests-ci.yml +++ b/.github/workflows/run-tests-ci.yml @@ -10,7 +10,7 @@ on: paths: - 'examples/**' - 'test-scripts/**' - - 'Dockerfile' + - 'test-scripts/linux/Dockerfile' - '.github/workflows/run-tests-ci.yml' # Run on pull requests to main branch pull_request: @@ -18,7 +18,7 @@ on: paths: - 'examples/**' - 'test-scripts/**' - - 'Dockerfile' + - 'test-scripts/linux/Dockerfile' - '.github/workflows/run-tests-ci.yml' # Allow manual triggering with custom parameters workflow_dispatch: @@ -41,7 +41,7 @@ on: # Global environment variables env: - SDK_VERSION: '9.0.0' + SDK_VERSION: '0.1000.4' jobs: test-x86_64: @@ -58,10 +58,11 @@ jobs: - name: Build Docker image (x86_64) run: | docker build \ + -f test-scripts/linux/Dockerfile \ --build-arg SDK_VERSION=${{ inputs.sdk_version || env.SDK_VERSION }} \ --build-arg ARCH=linux-x86_64 \ --build-arg SCANBOT_LICENSE="${{ secrets.SCANBOT_LICENSE_KEY }}" \ - --target all-tests \ + --target sdk-verification \ -t scanbot-linux-x86_64:latest . # Run the test suite with secure stdin approach @@ -73,34 +74,34 @@ jobs: docker run --rm \ -e SCANBOT_LICENSE="${{ secrets.SCANBOT_LICENSE_KEY }}" \ scanbot-linux-x86_64:latest \ - bash -c '/tests/test-python.sh 2>&1 | tee /tmp/test.log' + bash -o pipefail -c '/tests/test-python.sh 2>&1 | tee /tmp/test.log' ;; "java") echo "Running Java tests..." docker run --rm \ -e SCANBOT_LICENSE="${{ secrets.SCANBOT_LICENSE_KEY }}" \ scanbot-linux-x86_64:latest \ - bash -c '/tests/test-java.sh 2>&1 | tee /tmp/test.log' + bash -o pipefail -c '/tests/test-java.sh 2>&1 | tee /tmp/test.log' ;; "nodejs") echo "Running Node.js tests..." docker run --rm \ -e SCANBOT_LICENSE="${{ secrets.SCANBOT_LICENSE_KEY }}" \ scanbot-linux-x86_64:latest \ - bash -c '/tests/test-nodejs.sh 2>&1 | tee /tmp/test.log' + bash -o pipefail -c '/tests/test-nodejs.sh 2>&1 | tee /tmp/test.log' ;; "c") echo "Running C tests..." docker run --rm \ -e SCANBOT_LICENSE="${{ secrets.SCANBOT_LICENSE_KEY }}" \ scanbot-linux-x86_64:latest \ - bash -c '/tests/test-c.sh 2>&1 | tee /tmp/test.log' + bash -o pipefail -c '/tests/test-c.sh 2>&1 | tee /tmp/test.log' ;; "all"|*) echo "Running all tests..." docker run --rm \ -e SCANBOT_LICENSE="${{ secrets.SCANBOT_LICENSE_KEY }}" \ scanbot-linux-x86_64:latest \ - bash -c '/tests/run-all-tests.sh 2>&1 | tee /tmp/test.log' + bash -o pipefail -c '/tests/run-all-tests.sh 2>&1 | tee /tmp/test.log' ;; esac diff --git a/Readme.md b/Readme.md index 874734e..e5bddcd 100644 --- a/Readme.md +++ b/Readme.md @@ -66,6 +66,13 @@ A trial license key is required for evaluation or testing. To get a free trial l The test scripts validate SDK integration, detect compilation errors, and check license issues across all supported languages (Python, Java, Node.js, C). [Detailed documentation](test-scripts/README.md) +## Example projects + +- [Python example](examples/python/README.md) +- [Java example](examples/java/README.md) +- [Node.js example](examples/nodejs/README.md) +- [C example](examples/c/README.md) + ## Other supported platforms The Scanbot SDK is also available on Android, iOS, and most common cross-platform environments, such as React Native, Flutter, and .NET MAUI: diff --git a/examples/c/CMakeLists.txt b/examples/c/CMakeLists.txt index 19a8676..68447fa 100644 --- a/examples/c/CMakeLists.txt +++ b/examples/c/CMakeLists.txt @@ -1,17 +1,24 @@ +# 3.10 is the version shipped with Ubuntu 18.04, which is the base of NVIDIA JetPack 4.6. cmake_minimum_required(VERSION 3.10) project(scanbotsdk_c_example C) set(CMAKE_C_STANDARD 99) # Find or download Scanbot SDK if(NOT SCANBOTSDK_VERSION) - message(FATAL_ERROR "SCANBOTSDK_VERSION is not set.") + set(SCANBOTSDK_VERSION "0.1000.4") endif() -set(CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/cmake/") -set(SCANBOTSDK_DIR "${CMAKE_CURRENT_BINARY_DIR}/scanbotsdk") +set(CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/cmake" ${CMAKE_MODULE_PATH}) find_package(ScanbotSDK REQUIRED) -file(GLOB_RECURSE SOURCE_FILES CONFIGURE_DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/src/*.c) +file(GLOB_RECURSE SOURCE_FILES "${CMAKE_CURRENT_SOURCE_DIR}/src/*.c") add_executable(scanbotsdk_example ${SOURCE_FILES}) target_include_directories(scanbotsdk_example PRIVATE include) -target_link_libraries(scanbotsdk_example PRIVATE scanbotsdk) +target_link_libraries(scanbotsdk_example PRIVATE ScanbotSDK::ScanbotSDK) +if(WIN32) + add_custom_command(TARGET scanbotsdk_example POST_BUILD + COMMAND "${CMAKE_COMMAND}" -E copy_if_different + "$" + "$" + ) +endif() diff --git a/examples/c/README.md b/examples/c/README.md index 2061c15..a701b13 100644 --- a/examples/c/README.md +++ b/examples/c/README.md @@ -4,10 +4,10 @@ > Scanbot SDK requires Jetpack 6.1, CUDA 12.6 and TensorRT 10.3 to run with GPU acceleration. -* Install a C compiler, CMake and wget: +* Install a C compiler and CMake: ```bash -sudo apt install -y cmake build-essential wget +sudo apt install -y cmake build-essential ``` * Optionally, install CUDA and TensorRT for GPU acceleration. Make sure that you're running a supported Jetpack version. @@ -29,36 +29,65 @@ sudo jetson_clocks --restore * You're now ready to run the examples. ----- - ### Raspberry Pi OS, Ubuntu, Debian -* Install a C compiler, CMake and wget: +* Install a C compiler and CMake: ```bash -sudo apt install -y cmake build-essential wget +sudo apt install -y cmake build-essential ``` * You're now ready to build the examples. +### Windows + +Requirements: + +* Visual Studio C++ Build Tools +* CMake 3.10+ +* Recommended: ninja + ## Building the Examples In order to build all examples, run the following commands: -```bash -mkdir build -cd build -# Replace `` with the actual version number of the SDK you want to install. -cmake -DSCANBOTSDK_VERSION= .. -make -``` +* With Ninja (recommended): + ```bash + mkdir build + cd build + # Replace `` with the actual version number of the SDK you want to install. + cmake -GNinja -DSCANBOTSDK_VERSION= .. + ninja + ``` + +* With Unix Makefiles: + + ```bash + mkdir build + cd build + # Replace `` with the actual version number of the SDK you want to install. + cmake -DSCANBOTSDK_VERSION= .. + make + ``` + +* With Visual Studio (Windows-only): + + ```powershell + mkdir build + cd build + # Replace `` with the actual version number of the SDK you want to install. + cmake "-DSCANBOTSDK_VERSION=" .. + msbuild scanbotsdk_c_example.sln + # scanbotsdk_example.exe will be created under Debug\ + ``` + ## Usage The example supports five modes: **scan**, **analyze**, **enhance**, **parse**, and **live**. ```bash ./scanbotsdk_example scan --file [--license ] ./scanbotsdk_example analyze --file [--save ] [--license ] -./scanbotsdk_example enhance --file [--license ] +./scanbotsdk_example enhance --file [--save ] [--mask ] [--license ] ./scanbotsdk_example parse --text "" [--license ] ./scanbotsdk_example live --file [--license ] [--use_tensorrt] ``` @@ -68,7 +97,8 @@ The example supports five modes: **scan**, **analyze**, **enhance**, **parse**, ./scanbotsdk_example scan barcode --file images/example.jpg --license ./scanbotsdk_example analyze analyze_multi_page --file files/doc.pdf --license ./scanbotsdk_example analyze crop_analyze --file images/doc.jpg --save out/crop.jpg --license -./scanbotsdk_example enhance document --file images/doc.jpg --license +./scanbotsdk_example enhance straighten_document --file images/doc.jpg --license +./scanbotsdk_example enhance cleanup_document --file ../../test-scripts/test-images/highlighted.png --mask ../../test-scripts/test-images/highlighted_mask_001.png --save out/cleaned.jpg --license ./scanbotsdk_example parse mrz --text "P ./scanbotsdk_example live barcode --file images/example.jpg --license ``` diff --git a/examples/c/cmake/Download.cmake b/examples/c/cmake/Download.cmake new file mode 100644 index 0000000..396312b --- /dev/null +++ b/examples/c/cmake/Download.cmake @@ -0,0 +1,17 @@ +# Download.cmake +if(NOT URL OR NOT DEST) + message(FATAL_ERROR "Both URL and DEST variables must be defined.") +endif() + +file(DOWNLOAD "${URL}" "${DEST}" + STATUS status + TLS_VERIFY ON +) + +list(GET status 0 status_code) +list(GET status 1 status_string) + +if(NOT status_code EQUAL 0) + file(REMOVE "${DEST}") + message(FATAL_ERROR "Download failed (${status_code}): ${status_string}") +endif() diff --git a/examples/c/cmake/FindScanbotSDK.cmake b/examples/c/cmake/FindScanbotSDK.cmake index d6fabb8..816d27b 100644 --- a/examples/c/cmake/FindScanbotSDK.cmake +++ b/examples/c/cmake/FindScanbotSDK.cmake @@ -1,47 +1,107 @@ -include(ExternalProject) include(FindPackageHandleStandardArgs) -if(NOT SCANBOTSDK_DIR) -message(FATAL_ERROR "SCANBOTSDK_DIR not set") +if(TARGET ScanbotSDK::ScanbotSDK) + return() endif() -if (NOT EXISTS ${SCANBOTSDK_DIR}) +if(NOT DEFINED SCANBOTSDK_VERSION) + message(FATAL_ERROR "SCANBOTSDK_VERSION is not set.") +endif() + +if(NOT DEFINED SCANBOTSDK_DIR) + set(SCANBOTSDK_DIR "${CMAKE_CURRENT_BINARY_DIR}") +endif() + +if(NOT EXISTS "${SCANBOTSDK_DIR}/scanbotsdk") + if(CMAKE_SYSTEM_NAME STREQUAL "Windows") + if(CMAKE_SIZEOF_VOID_P EQUAL 4) + set(SCANBOTSDK_TARGET "windows-x86") + else() + set(SCANBOTSDK_TARGET "windows-x64") + endif() + elseif(CMAKE_SYSTEM_NAME STREQUAL "Linux") + if(CMAKE_SYSTEM_PROCESSOR MATCHES ".*arm.*" OR CMAKE_SYSTEM_PROCESSOR MATCHES ".*aarch64.*") + set(SCANBOTSDK_TARGET "linux-aarch64") + else() + set(SCANBOTSDK_TARGET "linux-x86_64") + endif() + else() + message(FATAL_ERROR "System ${CMAKE_SYSTEM_NAME} not supported") + endif() - find_program(WGET_PATH wget REQUIRED) + set(_archive "${SCANBOTSDK_DIR}/scanbotsdk-${SCANBOTSDK_VERSION}-${SCANBOTSDK_TARGET}.tar.gz") + set(_url "https://github.com/doo/scanbot-sdk-example-linux/releases/download/standalone-sdk%2Fv${SCANBOTSDK_VERSION}/scanbotsdk-${SCANBOTSDK_VERSION}-${SCANBOTSDK_TARGET}.tar.gz") - message(STATUS "Downloading ScanbotSDK ${SCANBOTSDK_VERSION} to ${SCANBOTSDK_DIR}") + file(MAKE_DIRECTORY "${SCANBOTSDK_DIR}") - if ("${CMAKE_HOST_SYSTEM_PROCESSOR}" MATCHES ".*arm.*" OR "${CMAKE_HOST_SYSTEM_PROCESSOR}" MATCHES ".*aarch64.*") - set(SCANBOTSDK_ARCHITECTURE "aarch64") - else () - set(SCANBOTSDK_ARCHITECTURE "x86_64") - endif () - string(TOLOWER "${CMAKE_HOST_SYSTEM_NAME}-${SCANBOTSDK_ARCHITECTURE}" PLATFORM_ID) - set(URL "https://github.com/doo/scanbot-sdk-example-linux/releases/download/standalone-sdk%2Fv${SCANBOTSDK_VERSION}/scanbotsdk-${SCANBOTSDK_VERSION}-linux-${SCANBOTSDK_ARCHITECTURE}.tar.gz") execute_process( - COMMAND ${WGET_PATH} "${URL}" - WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR} + COMMAND "${CMAKE_COMMAND}" + "-DURL=${_url}" + "-DDEST=${_archive}" + -P "${CMAKE_CURRENT_LIST_DIR}/Download.cmake" + RESULT_VARIABLE _rc ) + if(NOT _rc EQUAL 0) + file(REMOVE "${_archive}") + message(FATAL_ERROR "Failed to download Scanbot SDK from ${_url}") + endif() + execute_process( - COMMAND tar -xf scanbotsdk-${SCANBOTSDK_VERSION}-${PLATFORM_ID}.tar.gz - WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR} + COMMAND "${CMAKE_COMMAND}" -E tar -xf "${_archive}" + WORKING_DIRECTORY "${SCANBOTSDK_DIR}" + RESULT_VARIABLE _rc ) + if(NOT _rc EQUAL 0) + file(REMOVE "${_archive}") + file(REMOVE_RECURSE "${SCANBOTSDK_DIR}/scanbotsdk") + message(FATAL_ERROR "Failed to extract Scanbot SDK archive ${_archive}") + endif() + + file(REMOVE "${_archive}") endif() find_library(ScanbotSDK_LIBS - NAMES libscanbotsdk.so - HINTS ${SCANBOTSDK_DIR}/lib/ - ) + NAMES scanbotsdk + PATHS "${SCANBOTSDK_DIR}/scanbotsdk/lib" + NO_DEFAULT_PATH +) find_path(ScanbotSDK_INCLUDE_DIRS NAMES ScanbotSDK.h - HINTS ${SCANBOTSDK_DIR}/include/) + PATHS "${SCANBOTSDK_DIR}/scanbotsdk/include" + NO_DEFAULT_PATH +) + +set(SCANBOTSDK_REQUIRED_VARS ScanbotSDK_LIBS ScanbotSDK_INCLUDE_DIRS) + +if(WIN32) + find_file(ScanbotSDK_DLL + NAMES scanbotsdk.dll + PATHS "${SCANBOTSDK_DIR}/scanbotsdk/lib" + NO_DEFAULT_PATH + ) + list(APPEND SCANBOTSDK_REQUIRED_VARS ScanbotSDK_DLL) +endif() find_package_handle_standard_args(ScanbotSDK - REQUIRED_VARS ScanbotSDK_LIBS ScanbotSDK_INCLUDE_DIRS) + REQUIRED_VARS ${SCANBOTSDK_REQUIRED_VARS} + VERSION_VAR SCANBOTSDK_VERSION +) + +message(STATUS "Scanbot SDK third-party licenses are located at: ${SCANBOTSDK_DIR}/scanbotsdk/licenses/Libraries.txt") -add_library(scanbotsdk SHARED IMPORTED) -set_target_properties(scanbotsdk PROPERTIES - IMPORTED_LOCATION "${ScanbotSDK_LIBS}" - INTERFACE_INCLUDE_DIRECTORIES "${ScanbotSDK_INCLUDE_DIRS}" -) \ No newline at end of file +add_library(ScanbotSDK::ScanbotSDK SHARED IMPORTED) +set_target_properties(ScanbotSDK::ScanbotSDK PROPERTIES + INTERFACE_INCLUDE_DIRECTORIES "${ScanbotSDK_INCLUDE_DIRS}" +) + +if(WIN32) + set_target_properties(ScanbotSDK::ScanbotSDK PROPERTIES + IMPORTED_LOCATION "${ScanbotSDK_DLL}" + IMPORTED_IMPLIB "${ScanbotSDK_LIBS}" + ) +else() + set_target_properties(ScanbotSDK::ScanbotSDK PROPERTIES + IMPORTED_LOCATION "${ScanbotSDK_LIBS}" + ) +endif() diff --git a/examples/c/include/snippets/document/document_cleanup.h b/examples/c/include/snippets/document/document_cleanup.h new file mode 100644 index 0000000..bd6d91e --- /dev/null +++ b/examples/c/include/snippets/document/document_cleanup.h @@ -0,0 +1,12 @@ +#ifndef DOCUMENT_CLEANUP_H +#define DOCUMENT_CLEANUP_H + +#include + +scanbotsdk_error_code_t document_cleanup( + scanbotsdk_image_t *image, + scanbotsdk_image_t *mask, + const char *save_path +); + +#endif diff --git a/examples/c/include/snippets/document/document_straightener.h b/examples/c/include/snippets/document/document_straightener.h new file mode 100644 index 0000000..1c63bc7 --- /dev/null +++ b/examples/c/include/snippets/document/document_straightener.h @@ -0,0 +1,8 @@ +#ifndef DOCUMENT_STRAIGHTENER_H +#define DOCUMENT_STRAIGHTENER_H + +#include + +scanbotsdk_error_code_t straighten_document(scanbotsdk_image_t *image); + +#endif diff --git a/examples/c/include/snippets/enhancer/document_enhancer.h b/examples/c/include/snippets/enhancer/document_enhancer.h deleted file mode 100644 index 6826eea..0000000 --- a/examples/c/include/snippets/enhancer/document_enhancer.h +++ /dev/null @@ -1,8 +0,0 @@ -#ifndef DOCUMENT_ENHANCER_H -#define DOCUMENT_ENHANCER_H - -#include - -scanbotsdk_error_code_t enhance_document(scanbotsdk_image_t *image); - -#endif diff --git a/examples/c/src/main.c b/examples/c/src/main.c index 865ccae..0f88f0d 100644 --- a/examples/c/src/main.c +++ b/examples/c/src/main.c @@ -21,7 +21,8 @@ #include #include #include -#include +#include +#include #include @@ -35,6 +36,7 @@ int main(int argc, char *argv[]) { char *command = argv[2]; const char *file_path = get_flag(argc, argv, "--file"); const char *save_path = get_flag(argc, argv, "--save"); + const char *mask_path = get_flag(argc, argv, "--mask"); const char *text_input = get_flag(argc, argv, "--text"); const char *license_arg = get_flag(argc, argv, "--license"); bool use_tensor_rt = get_flag(argc, argv, "--use_tensorrt") != NULL; // live only, tensor rt accelerator @@ -47,6 +49,7 @@ int main(int argc, char *argv[]) { params.writeable_path = "."; scanbotsdk_image_t *image = NULL; + scanbotsdk_image_t *mask_image = NULL; scanbotsdk_error_code_t ec = scanbotsdk_initialize(¶ms); if (ec != SCANBOTSDK_OK) { fprintf(stderr, "initialize: %d: %s\n", ec, error_message(ec)); goto cleanup; } @@ -72,10 +75,23 @@ int main(int argc, char *argv[]) { else if (strcmp(category, "enhance") == 0) { if (!file_path) { print_usage(argv[0]); ec = SCANBOTSDK_ERROR_INVALID_ARGUMENT; goto cleanup; } - ec = load_image_from_path(file_path, &image); - if (ec != SCANBOTSDK_OK) goto cleanup; + if (strcmp(command, "straighten_document") == 0) { + ec = load_image_from_path(file_path, &image); + if (ec != SCANBOTSDK_OK) goto cleanup; + + ec = straighten_document(image); + } + else if (strcmp(command, "cleanup_document") == 0) { + if (!mask_path) { print_usage(argv[0]); ec = SCANBOTSDK_ERROR_INVALID_ARGUMENT; goto cleanup; } - if (strcmp(command, "document") == 0) ec = enhance_document(image); + ec = load_image_from_path(file_path, &image); + if (ec != SCANBOTSDK_OK) goto cleanup; + + ec = load_image_from_path(mask_path, &mask_image); + if (ec != SCANBOTSDK_OK) goto cleanup; + + ec = document_cleanup(image, mask_image, save_path); + } else { print_usage(argv[0]); ec = SCANBOTSDK_ERROR_INVALID_ARGUMENT; } } else if (strcmp(category, "analyze") == 0) { @@ -107,6 +123,7 @@ int main(int argc, char *argv[]) { else { print_usage(argv[0]); ec = SCANBOTSDK_ERROR_INVALID_ARGUMENT; } cleanup: + scanbotsdk_image_free(mask_image); scanbotsdk_image_free(image); return (ec == SCANBOTSDK_OK) ? 0 : 1; } \ No newline at end of file diff --git a/examples/c/src/snippets/barcode/detect_barcode.c b/examples/c/src/snippets/barcode/detect_barcode.c index fd33cf6..1b213f7 100644 --- a/examples/c/src/snippets/barcode/detect_barcode.c +++ b/examples/c/src/snippets/barcode/detect_barcode.c @@ -21,10 +21,10 @@ scanbotsdk_error_code_t print_barcodes_result(scanbotsdk_barcode_scanner_result_ if (ec != SCANBOTSDK_OK) { fprintf(stderr, "get_barcodes: %d: %s\n", ec, error_message(ec)); goto cleanup; } for (size_t i = 0; i < count; ++i) { - const char *text = NULL; + scanbotsdk_u8string_ref_t text_ref = {0}; scanbotsdk_generic_document_t *doc = NULL; - - scanbotsdk_barcode_item_get_text(barcodes[i], &text); + scanbotsdk_barcode_item_get_text(barcodes[i], &text_ref); + const char *text = scanbotsdk_u8string_ref_assume_cstring(text_ref); fprintf(stdout, " %zu) %s\n", i + 1, text); scanbotsdk_barcode_item_get_extracted_document(barcodes[i], &doc); @@ -65,4 +65,3 @@ scanbotsdk_error_code_t detect_barcode(scanbotsdk_image_t *image) { scanbotsdk_barcode_scanner_configuration_free(config); return ec; } - diff --git a/examples/c/src/snippets/barcode/parse_barcode_document.c b/examples/c/src/snippets/barcode/parse_barcode_document.c index bebab44..3739d71 100644 --- a/examples/c/src/snippets/barcode/parse_barcode_document.c +++ b/examples/c/src/snippets/barcode/parse_barcode_document.c @@ -30,7 +30,8 @@ scanbotsdk_error_code_t parse_barcode_document(const char* raw_string) { ec = scanbotsdk_barcode_document_parser_create(formats, formats_count, &parser); if (ec != SCANBOTSDK_OK) { fprintf(stderr, "create_parser: %d: %s\n", ec, error_message(ec)); goto cleanup; } - ec = scanbotsdk_barcode_document_parser_parse(parser, raw_string, &result); + scanbotsdk_u8string_ref_t raw_ref = scanbotsdk_u8string_ref_from_cstring(raw_string); + ec = scanbotsdk_barcode_document_parser_parse(parser, raw_ref, &result); if (ec != SCANBOTSDK_OK) { fprintf(stderr, "parser_parse: %d: %s\n", ec, error_message(ec)); goto cleanup; } ec = scanbotsdk_barcode_document_parser_result_get_parsed_document(result, &parsed_doc); @@ -49,4 +50,3 @@ scanbotsdk_error_code_t parse_barcode_document(const char* raw_string) { scanbotsdk_barcode_document_parser_free(parser); return ec; } - diff --git a/examples/c/src/snippets/datacapture/medical_certificate_scanner.c b/examples/c/src/snippets/datacapture/medical_certificate_scanner.c index 68b1afa..3c7cbf9 100644 --- a/examples/c/src/snippets/datacapture/medical_certificate_scanner.c +++ b/examples/c/src/snippets/datacapture/medical_certificate_scanner.c @@ -25,12 +25,13 @@ scanbotsdk_error_code_t print_medical_certificate_result(scanbotsdk_medical_cert for (size_t i = 0; i < count; ++i) { scanbotsdk_medical_certificate_patient_info_field_type_t type; - const char* value = NULL; + scanbotsdk_u8string_ref_t value_ref = {0}; scanbotsdk_medical_certificate_patient_info_field_get_type(fields[i], &type); - scanbotsdk_medical_certificate_patient_info_field_get_value(fields[i], &value); + scanbotsdk_medical_certificate_patient_info_field_get_value(fields[i], &value_ref); + const char *value = scanbotsdk_u8string_ref_assume_cstring(value_ref); - fprintf(stderr, "Type: %d Value: %s\n", type, value); + fprintf(stderr, "Type: %d Value: %s\n", type, value ? value : ""); } cleanup: diff --git a/examples/c/src/snippets/datacapture/mrz_parser.c b/examples/c/src/snippets/datacapture/mrz_parser.c index f319645..26dd4a7 100644 --- a/examples/c/src/snippets/datacapture/mrz_parser.c +++ b/examples/c/src/snippets/datacapture/mrz_parser.c @@ -19,7 +19,8 @@ scanbotsdk_error_code_t parse_mrz(const char* text) { ec = scanbotsdk_mrz_parser_create(config, &parser); if (ec != SCANBOTSDK_OK) { fprintf(stderr, "create_parser: %d: %s\n", ec, error_message(ec)); goto cleanup; } - ec = scanbotsdk_mrz_parser_parse(parser, text, &result); + scanbotsdk_u8string_ref_t text_ref = scanbotsdk_u8string_ref_from_cstring(text); + ec = scanbotsdk_mrz_parser_parse(parser, text_ref, &result); if (ec != SCANBOTSDK_OK) { fprintf(stderr, "parse: %d: %s\n", ec, error_message(ec)); goto cleanup; } ec = scanbotsdk_mrz_scanner_result_get_document(result, &mrz); @@ -38,4 +39,3 @@ scanbotsdk_error_code_t parse_mrz(const char* text) { scanbotsdk_mrz_scanner_result_free(result); return ec; } - diff --git a/examples/c/src/snippets/datacapture/ocr.c b/examples/c/src/snippets/datacapture/ocr.c index 34f9056..6abafb5 100644 --- a/examples/c/src/snippets/datacapture/ocr.c +++ b/examples/c/src/snippets/datacapture/ocr.c @@ -5,8 +5,9 @@ #include static void print_ocr_element_text(scanbotsdk_ocr_element_t *el, const char *label, int indent) { - const char *text = NULL; - scanbotsdk_ocr_element_get_text(el, &text); + scanbotsdk_u8string_ref_t text_ref = {0}; + scanbotsdk_ocr_element_get_text(el, &text_ref); + const char *text = scanbotsdk_u8string_ref_assume_cstring(text_ref); for (int i = 0; i < indent; i++) printf(" "); printf("%s: \"%s\"\n", label, text ? text : ""); diff --git a/examples/c/src/snippets/datacapture/text_pattern_scanner.c b/examples/c/src/snippets/datacapture/text_pattern_scanner.c index acff3cf..f843747 100644 --- a/examples/c/src/snippets/datacapture/text_pattern_scanner.c +++ b/examples/c/src/snippets/datacapture/text_pattern_scanner.c @@ -6,11 +6,12 @@ scanbotsdk_error_code_t print_text_pattern_result(scanbotsdk_text_pattern_scanner_result_t *result) { scanbotsdk_error_code_t ec; - const char* raw_text; + scanbotsdk_u8string_ref_t raw_text_ref = {0}; + const char *raw_text = NULL; - ec = scanbotsdk_text_pattern_scanner_result_get_raw_text(result, &raw_text); + ec = scanbotsdk_text_pattern_scanner_result_get_raw_text(result, &raw_text_ref); if (ec != SCANBOTSDK_OK) { fprintf(stderr, "get_raw_text: %d\n", ec); return ec; } - + raw_text = scanbotsdk_u8string_ref_assume_cstring(raw_text_ref); printf("Raw Text: %s\n", raw_text); return ec; } diff --git a/examples/c/src/snippets/datacapture/vin_scanner.c b/examples/c/src/snippets/datacapture/vin_scanner.c index 0b974cd..28509b3 100644 --- a/examples/c/src/snippets/datacapture/vin_scanner.c +++ b/examples/c/src/snippets/datacapture/vin_scanner.c @@ -7,10 +7,11 @@ scanbotsdk_error_code_t print_vin_result(scanbotsdk_vin_scanner_result_t *result) { scanbotsdk_error_code_t ec = SCANBOTSDK_OK; scanbotsdk_text_pattern_scanner_result_t *text_result; - const char* raw_text; + scanbotsdk_u8string_ref_t raw_text_ref = {0}; scanbotsdk_vin_scanner_result_get_text_result(result, &text_result); - scanbotsdk_text_pattern_scanner_result_get_raw_text(text_result, &raw_text); + scanbotsdk_text_pattern_scanner_result_get_raw_text(text_result, &raw_text_ref); + const char* raw_text = scanbotsdk_u8string_ref_assume_cstring(raw_text_ref); printf("Text: %s\n", raw_text); return ec; diff --git a/examples/c/src/snippets/document/document_cleanup.c b/examples/c/src/snippets/document/document_cleanup.c new file mode 100644 index 0000000..f141e5e --- /dev/null +++ b/examples/c/src/snippets/document/document_cleanup.c @@ -0,0 +1,113 @@ +#include + +#include +#include + +scanbotsdk_error_code_t document_cleanup( + scanbotsdk_image_t *image, + scanbotsdk_image_t *mask, + const char *save_path +) { + scanbotsdk_error_code_t ec = SCANBOTSDK_OK; + scanbotsdk_document_cleanup_configuration_t *configuration = NULL; + scanbotsdk_document_cleanup_t *cleanup = NULL; + scanbotsdk_document_cleanup_result_t *result = NULL; + scanbotsdk_document_cleanup_status_t status; + const char *status_str = NULL; + + scanbotsdk_image_t *cleaned_image = NULL; + scanbotsdk_image_info_t *original_info = NULL; + scanbotsdk_image_info_t *cleaned_info = NULL; + int original_width = 0; + int original_height = 0; + int cleaned_width = 0; + int cleaned_height = 0; + + scanbotsdk_save_image_options_t *save_options = NULL; + + ec = scanbotsdk_document_cleanup_configuration_create_with_defaults(&configuration); + if (ec != SCANBOTSDK_OK) { + fprintf(stderr, "document_cleanup_configuration_create_with_defaults: %d: %s\n", ec, error_message(ec)); + goto cleanup; + } + + ec = scanbotsdk_document_cleanup_create(image, configuration, &cleanup); + if (ec != SCANBOTSDK_OK) { + fprintf(stderr, "document_cleanup_create: %d: %s\n", ec, error_message(ec)); + goto cleanup; + } + + ec = scanbotsdk_document_cleanup_run(cleanup, mask, &result); + if (ec != SCANBOTSDK_OK) { + fprintf(stderr, "document_cleanup_run: %d: %s\n", ec, error_message(ec)); + goto cleanup; + } + + ec = scanbotsdk_document_cleanup_result_get_status(result, &status); + if (ec != SCANBOTSDK_OK) { + fprintf(stderr, "document_cleanup_result_get_status: %d: %s\n", ec, error_message(ec)); + goto cleanup; + } + + ec = scanbotsdk_document_cleanup_status_t_to_string(status, &status_str); + if (ec != SCANBOTSDK_OK) { + fprintf(stderr, "document_cleanup_status_t_to_string: %d: %s\n", ec, error_message(ec)); + goto cleanup; + } + + printf("Document cleanup status: %s\n", status_str); + + ec = scanbotsdk_image_info(image, &original_info); + if (ec != SCANBOTSDK_OK) { + fprintf(stderr, "image_info(original): %d: %s\n", ec, error_message(ec)); + goto cleanup; + } + + ec = scanbotsdk_document_cleanup_result_get_image(result, &cleaned_image); + if (ec != SCANBOTSDK_OK || cleaned_image == NULL) { + fprintf(stderr, "document_cleanup_result_get_image: %d: %s\n", ec, error_message(ec)); + goto cleanup; + } + + ec = scanbotsdk_image_info(cleaned_image, &cleaned_info); + if (ec != SCANBOTSDK_OK) { + fprintf(stderr, "image_info(cleaned): %d: %s\n", ec, error_message(ec)); + goto cleanup; + } + + ec = scanbotsdk_image_info_get_width(original_info, &original_width); + if (ec != SCANBOTSDK_OK) { fprintf(stderr, "image_info_get_width(original): %d: %s\n", ec, error_message(ec)); goto cleanup; } + ec = scanbotsdk_image_info_get_height(original_info, &original_height); + if (ec != SCANBOTSDK_OK) { fprintf(stderr, "image_info_get_height(original): %d: %s\n", ec, error_message(ec)); goto cleanup; } + ec = scanbotsdk_image_info_get_width(cleaned_info, &cleaned_width); + if (ec != SCANBOTSDK_OK) { fprintf(stderr, "image_info_get_width(cleaned): %d: %s\n", ec, error_message(ec)); goto cleanup; } + ec = scanbotsdk_image_info_get_height(cleaned_info, &cleaned_height); + if (ec != SCANBOTSDK_OK) { fprintf(stderr, "image_info_get_height(cleaned): %d: %s\n", ec, error_message(ec)); goto cleanup; } + + printf("Original WxH: %dx%d\n", original_width, original_height); + printf("Cleaned WxH: %dx%d\n", cleaned_width, cleaned_height); + + if (save_path && save_path[0] != '\0') { + ec = scanbotsdk_save_image_options_create_with_defaults(&save_options); + if (ec != SCANBOTSDK_OK) { + fprintf(stderr, "save_image_options_create_with_defaults: %d: %s\n", ec, error_message(ec)); + goto cleanup; + } + + ec = scanbotsdk_image_save(cleaned_image, save_path, save_options); + if (ec != SCANBOTSDK_OK) { + fprintf(stderr, "image_save: %d: %s\n", ec, error_message(ec)); + goto cleanup; + } + printf("Saved cleaned image to: %s\n", save_path); + } + +cleanup: + scanbotsdk_save_image_options_free(save_options); + scanbotsdk_image_info_free(cleaned_info); + scanbotsdk_image_info_free(original_info); + scanbotsdk_document_cleanup_result_free(result); + scanbotsdk_document_cleanup_free(cleanup); + scanbotsdk_document_cleanup_configuration_free(configuration); + return ec; +} diff --git a/examples/c/src/snippets/enhancer/document_enhancer.c b/examples/c/src/snippets/document/document_straightener.c similarity index 79% rename from examples/c/src/snippets/enhancer/document_enhancer.c rename to examples/c/src/snippets/document/document_straightener.c index dc637e1..d09d79d 100644 --- a/examples/c/src/snippets/enhancer/document_enhancer.c +++ b/examples/c/src/snippets/document/document_straightener.c @@ -1,15 +1,15 @@ #include #include -#include +#include #include -scanbotsdk_error_code_t enhance_document(scanbotsdk_image_t *image) { +scanbotsdk_error_code_t straighten_document(scanbotsdk_image_t *image) { scanbotsdk_error_code_t ec = SCANBOTSDK_OK; scanbotsdk_document_straightening_result_t *result = NULL; scanbotsdk_document_straightening_parameters_t *straightening_params = NULL; - scanbotsdk_document_enhancer_t *enhancer = NULL; + scanbotsdk_document_straightener_t *straightener = NULL; scanbotsdk_image_t *straightened_image = NULL; scanbotsdk_aspect_ratio_t *aspect_ratios[4] = {0}; @@ -34,18 +34,18 @@ scanbotsdk_error_code_t enhance_document(scanbotsdk_image_t *image) { ); if (ec != SCANBOTSDK_OK) { fprintf(stderr, "document_straightening_parameters_create: %d: %s\n", ec, error_message(ec)); goto cleanup; } - ec = scanbotsdk_document_enhancer_create(&enhancer); - if (ec != SCANBOTSDK_OK) { fprintf(stderr, "document_enhancer_create: %d: %s\n", ec, error_message(ec)); goto cleanup; } + ec = scanbotsdk_document_straightener_create(&straightener); + if (ec != SCANBOTSDK_OK) { fprintf(stderr, "document_straightener_create: %d: %s\n", ec, error_message(ec)); goto cleanup; } - ec = scanbotsdk_document_enhancer_straighten( - enhancer, + ec = scanbotsdk_document_straightener_run( + straightener, image, straightening_params, NULL, 0, &result ); - if (ec != SCANBOTSDK_OK) { fprintf(stderr, "document_enhancer_straighten: %d: %s\n", ec, error_message(ec)); goto cleanup; } + if (ec != SCANBOTSDK_OK) { fprintf(stderr, "document_straighten: %d: %s\n", ec, error_message(ec)); goto cleanup; } ec = scanbotsdk_document_straightening_result_get_straightened_image(result, &straightened_image); if (ec != SCANBOTSDK_OK) { fprintf(stderr, "document_straightening_result_get_straightened_image: %d: %s\n", ec, error_message(ec)); goto cleanup; } @@ -57,7 +57,7 @@ scanbotsdk_error_code_t enhance_document(scanbotsdk_image_t *image) { /* straightened_image can be saved or processed further here */ cleanup: - scanbotsdk_document_enhancer_free(enhancer); + scanbotsdk_document_straightener_free(straightener); scanbotsdk_document_straightening_result_free(result); scanbotsdk_document_straightening_parameters_free(straightening_params); diff --git a/examples/c/src/snippets/live/live_barcode.c b/examples/c/src/snippets/live/live_barcode.c index 7a755b3..3c79aa8 100644 --- a/examples/c/src/snippets/live/live_barcode.c +++ b/examples/c/src/snippets/live/live_barcode.c @@ -128,8 +128,9 @@ scanbotsdk_error_code_t process_frame(scanbotsdk_barcode_scanner_t *scanner, fra scanbotsdk_barcode_scanner_result_get_barcodes(result, barcodes, count); for (size_t i = 0; i < count; i++) { - const char *text = NULL; - scanbotsdk_barcode_item_get_text(barcodes[i], &text); + scanbotsdk_u8string_ref_t text_ref = {0}; + scanbotsdk_barcode_item_get_text(barcodes[i], &text_ref); + const char *text = scanbotsdk_u8string_ref_assume_cstring(text_ref); fprintf(stdout, " Barcode %zu: %s\n", i, text); } free(barcodes); @@ -185,7 +186,8 @@ scanbotsdk_error_code_t create_barcode_scanner(bool use_tensor_rt, scanbotsdk_ba if (use_tensor_rt) { scanbotsdk_tensor_rt_accelerator_t *trt = NULL; - ec = scanbotsdk_tensor_rt_accelerator_create("./", &trt); + scanbotsdk_u8string_ref_t trt_dir = scanbotsdk_u8string_ref_from_cstring("./"); + ec = scanbotsdk_tensor_rt_accelerator_create(trt_dir, &trt); if (ec == SCANBOTSDK_OK) { scanbotsdk_tensor_rt_accelerator_as_scanbotsdk_accelerator(trt, &accelerator); diff --git a/examples/c/src/utils/utils.c b/examples/c/src/utils/utils.c index dd334a1..425492d 100644 --- a/examples/c/src/utils/utils.c +++ b/examples/c/src/utils/utils.c @@ -34,13 +34,15 @@ scanbotsdk_error_code_t print_generic_document_fields(scanbotsdk_generic_documen scanbotsdk_field_type_t *field_type = NULL; scanbotsdk_field_get_type(fields[i], &field_type); - const char *type_name = NULL; - scanbotsdk_field_type_get_name(field_type, &type_name); + scanbotsdk_u8string_ref_t type_name_ref = {0}; + scanbotsdk_field_type_get_name(field_type, &type_name_ref); + const char *type_name = scanbotsdk_u8string_ref_assume_cstring(type_name_ref); scanbotsdk_ocr_result_t *ocr_result = NULL; if (scanbotsdk_field_get_value(fields[i], &ocr_result) == SCANBOTSDK_OK && ocr_result) { - const char *text = NULL; - scanbotsdk_ocr_result_get_text(ocr_result, &text); + scanbotsdk_u8string_ref_t text_ref = {0}; + scanbotsdk_ocr_result_get_text(ocr_result, &text_ref); + const char *text = scanbotsdk_u8string_ref_assume_cstring(text_ref); printf("Field[%zu]: type=%s, value=\"%s\"\n", i, type_name, text ? text : "text value n/a"); } else { @@ -88,9 +90,9 @@ void print_usage(const char *prog) { printf("Usage:\n"); printf(" %s scan --file [--license ]\n", prog); printf("or\n"); - printf(" %s enhance --file [--license ]\n", prog); + printf(" %s enhance --file [--save ] [--mask ] [--license ]\n", prog); printf("or\n"); - printf(" %s analyze --file --save [--license ]\n", prog); + printf(" %s analyze --file [--save ] [--license ]\n", prog); printf("or\n"); printf(" %s parse --text \"\" [--license ]\n\n", prog); printf("or\n"); @@ -101,7 +103,7 @@ void print_usage(const char *prog) { printf(" medical_certificate | mrz | ocr | text_pattern | vin\n\n"); printf("Available enhance commands:\n"); - printf(" document \n\n"); + printf(" straighten_document | cleanup_document\n\n"); printf("Available analyze commands:\n"); printf(" analyze_multi_page | crop_analyze\n\n"); @@ -120,7 +122,8 @@ void print_usage(const char *prog) { "to an actual camera or live video feed.\n"); printf("Note:\n"); - printf(" The --save argument is optional and only used with analyze/crop_analyze.\n"); + printf(" The --save argument is optional and used with analyze/crop_analyze and enhance/cleanup_document.\n"); + printf(" The --mask argument is required for enhance/cleanup_document.\n"); printf(" The --license argument is optional. If not provided, the program will\n"); printf(" \tcheck the placeholder in main.c\n"); @@ -128,6 +131,8 @@ void print_usage(const char *prog) { printf(" %s scan barcode --file images/example.jpg --license \n", prog); printf(" %s analyze analyze_multi_page --file files/doc.pdf --license \n", prog); printf(" %s analyze crop_analyze --file images/doc.jpg --save out/crop.jpg --license \n", prog); + printf(" %s enhance straighten_document --file images/doc.jpg --license \n", prog); + printf(" %s enhance cleanup_document --file ../../test-scripts/test-images/highlighted.png --mask ../../test-scripts/test-images/highlighted_mask_001.png --save out/cleaned.jpg --license \n", prog); printf(" %s parse mrz --text \"P\n", prog); printf(" %s live barcode --file images/example.jpg --license \n", prog); printf("\n"); diff --git a/examples/java/README.md b/examples/java/README.md index dca0ae6..d52cdc0 100644 --- a/examples/java/README.md +++ b/examples/java/README.md @@ -13,9 +13,9 @@ The example supports four commands: **scan**, **analyze**, **enhance**, and **pa ```bash ./gradlew run --args='scan --file [--license ]' ./gradlew run --args='scan --resource [--license ]' -./gradlew run --args='analyze --file --save [--license ]' -./gradlew run --args='analyze --resource --save [--license ]' -./gradlew run --args='enhance --file [--license ]' +./gradlew run --args='analyze --file [--save ] [--license ]' +./gradlew run --args='analyze --resource [--save ] [--license ]' +./gradlew run --args='enhance --file [--save ] [--mask ] [--mask-resource ] [--license ]' ./gradlew run --args='parse --text "" [--license ]' ``` @@ -24,7 +24,8 @@ The example supports four commands: **scan**, **analyze**, **enhance**, and **pa ./gradlew run --args='scan barcode --file images/example.jpg --license ' ./gradlew run --args='analyze analyze_multi_page --resource files/doc.pdf --license ' ./gradlew run --args='analyze crop_analyze --file images/doc.jpg --save out/crop.jpg --license ' -./gradlew run --args='enhance document --file images/doc.jpg --license ' +./gradlew run --args='enhance straighten_document --file images/doc.jpg --license ' +./gradlew run --args='enhance cleanup_document --file ../../test-scripts/test-images/highlighted.png --mask ../../test-scripts/test-images/highlighted_mask_001.png --save out/cleaned.jpg --license ' ./gradlew run --args='parse mrz --text "P' ``` diff --git a/examples/java/build.gradle b/examples/java/build.gradle index fa7de16..beaed37 100644 --- a/examples/java/build.gradle +++ b/examples/java/build.gradle @@ -4,7 +4,7 @@ plugins { } // TODO Add your SCANBOTSDK_VERSION here. -def SCANBOTSDK_VERSION = "9.0.0" +def SCANBOTSDK_VERSION = "0.1000.4" def arch = System.getProperty("os.arch") def SCANBOTSDK_ARCHITECTURE = (arch.contains("arm") || arch.contains("aarch64")) ? "aarch64" : "x86_64" diff --git a/examples/java/src/main/java/io/scanbot/sdk/ScanbotSDKExample.java b/examples/java/src/main/java/io/scanbot/sdk/ScanbotSDKExample.java index e05c9c6..a34754e 100644 --- a/examples/java/src/main/java/io/scanbot/sdk/ScanbotSDKExample.java +++ b/examples/java/src/main/java/io/scanbot/sdk/ScanbotSDKExample.java @@ -7,7 +7,6 @@ import io.scanbot.sdk.snippets.barcode.*; import io.scanbot.sdk.snippets.datacapture.*; import io.scanbot.sdk.snippets.document.*; -import io.scanbot.sdk.snippets.enhancer.DocumentEnhancerSnippet; import io.scanbot.sdk.utils.*; import java.util.Arrays; @@ -28,6 +27,8 @@ public static void main(String[] args) throws Exception { final String file = f.get("--file"); final String resource = f.get("--resource"); final String save = f.get("--save"); + final String mask = f.get("--mask"); + final String maskResource = f.get("--mask-resource"); final String text = f.get("--text"); final String license = f.get("--license"); @@ -76,13 +77,20 @@ public static void main(String[] args) throws Exception { } case "enhance": { if (file == null && resource == null) { ExampleUsage.print(); return; } - try (ImageRef image = Utils.createImageRef(file, resource)) { - switch (subcommand) { - case "document": DocumentEnhancerSnippet.run(image); break; - default: ExampleUsage.print(); - } - break; + switch (subcommand) { + case "straighten_document": + try (ImageRef image = Utils.createImageRef(file, resource)) { + DocumentStraightenerSnippet.run(image); + } + break; + case "cleanup_document": + if (mask == null && maskResource == null) { ExampleUsage.print(); return; } + DocumentCleanupSnippet.run(file, resource, mask, maskResource, save); + break; + default: + ExampleUsage.print(); } + break; } case "parse": { if (text == null || text.trim().isEmpty()) { ExampleUsage.print(); return; } diff --git a/examples/java/src/main/java/io/scanbot/sdk/snippets/document/DocumentCleanupSnippet.java b/examples/java/src/main/java/io/scanbot/sdk/snippets/document/DocumentCleanupSnippet.java new file mode 100644 index 0000000..cf5edfc --- /dev/null +++ b/examples/java/src/main/java/io/scanbot/sdk/snippets/document/DocumentCleanupSnippet.java @@ -0,0 +1,38 @@ +package io.scanbot.sdk.snippets.document; + +import io.scanbot.sdk.image.ImageInfo; +import io.scanbot.sdk.image.ImageRef; +import io.scanbot.sdk.image.SaveImageOptions; +import io.scanbot.sdk.imageprocessing.DocumentCleanup; +import io.scanbot.sdk.imageprocessing.DocumentCleanupConfiguration; +import io.scanbot.sdk.imageprocessing.DocumentCleanupResult; +import io.scanbot.sdk.utils.Utils; + +public class DocumentCleanupSnippet { + public static void run( + String filePath, + String resourcePath, + String maskFilePath, + String maskResourcePath, + String savePath + ) throws Exception { + try ( + ImageRef image = Utils.createImageRef(filePath, resourcePath); + ImageRef mask = Utils.createImageRef(maskFilePath, maskResourcePath); + DocumentCleanup cleanup = new DocumentCleanup(image, new DocumentCleanupConfiguration()); + DocumentCleanupResult result = cleanup.run(mask) + ) { + System.out.println("Document cleanup status: " + result.getStatus()); + + ImageInfo originalInfo = image.imageInfo(); + ImageInfo cleanedInfo = result.getImage().imageInfo(); + System.out.printf("Original WxH: %dx%d%n", originalInfo.getWidth(), originalInfo.getHeight()); + System.out.printf("Cleaned WxH: %dx%d%n", cleanedInfo.getWidth(), cleanedInfo.getHeight()); + + if (savePath != null) { + result.getImage().saveImage(savePath, new SaveImageOptions()); + System.out.println("Saved cleaned image to: " + savePath); + } + } + } +} diff --git a/examples/java/src/main/java/io/scanbot/sdk/snippets/enhancer/DocumentEnhancerSnippet.java b/examples/java/src/main/java/io/scanbot/sdk/snippets/document/DocumentStraightenerSnippet.java similarity index 74% rename from examples/java/src/main/java/io/scanbot/sdk/snippets/enhancer/DocumentEnhancerSnippet.java rename to examples/java/src/main/java/io/scanbot/sdk/snippets/document/DocumentStraightenerSnippet.java index 4dbebb7..b867c62 100644 --- a/examples/java/src/main/java/io/scanbot/sdk/snippets/enhancer/DocumentEnhancerSnippet.java +++ b/examples/java/src/main/java/io/scanbot/sdk/snippets/document/DocumentStraightenerSnippet.java @@ -1,14 +1,14 @@ -package io.scanbot.sdk.snippets.enhancer; +package io.scanbot.sdk.snippets.document; import java.util.List; -import io.scanbot.sdk.documentscanner.DocumentEnhancer; +import io.scanbot.sdk.documentscanner.DocumentStraightener; import io.scanbot.sdk.documentscanner.DocumentStraighteningMode; import io.scanbot.sdk.documentscanner.DocumentStraighteningParameters; import io.scanbot.sdk.documentscanner.DocumentStraighteningResult; import io.scanbot.sdk.geometry.AspectRatio; import io.scanbot.sdk.image.ImageRef; -public class DocumentEnhancerSnippet { +public class DocumentStraightenerSnippet { public static void run(ImageRef image) throws Exception { DocumentStraighteningParameters params = new DocumentStraighteningParameters(); params.setStraighteningMode(DocumentStraighteningMode.STRAIGHTEN); @@ -20,8 +20,8 @@ public static void run(ImageRef image) throws Exception { )); try ( - DocumentEnhancer enhancer = new DocumentEnhancer(); - DocumentStraighteningResult result = enhancer.straighten(image, params, List.of()) + DocumentStraightener straightener = new DocumentStraightener(); + DocumentStraighteningResult result = straightener.run(image, params, List.of()) ) { // The straightened image can be accessed via result.getStraightenedImage() and saved or further processed as needed. } diff --git a/examples/java/src/main/java/io/scanbot/sdk/snippets/image/ImageProcessingSnippets.java b/examples/java/src/main/java/io/scanbot/sdk/snippets/image/ImageProcessingSnippets.java index c22de10..8b3562e 100644 --- a/examples/java/src/main/java/io/scanbot/sdk/snippets/image/ImageProcessingSnippets.java +++ b/examples/java/src/main/java/io/scanbot/sdk/snippets/image/ImageProcessingSnippets.java @@ -12,6 +12,7 @@ import io.scanbot.sdk.image.SaveImageOptions; import io.scanbot.sdk.imageprocessing.BinarizationFilterPreset; import io.scanbot.sdk.imageprocessing.CustomBinarizationFilter; +import io.scanbot.sdk.imageprocessing.DocumentCropOptimization; import io.scanbot.sdk.imageprocessing.ImageProcessor; public class ImageProcessingSnippets { @@ -73,7 +74,11 @@ public static void detectAndCropDocument(ImageRef image) throws Exception { System.out.println("Detection status: " + detectionResult.getStatus()); System.out.println("Detected points: " + detectionResult.getPoints().size()); - try (ImageRef cropped = processor.crop(image, detectionResult.getPointsNormalized())) { + try (ImageRef cropped = processor.crop( + image, + detectionResult.getPointsNormalized(), + DocumentCropOptimization.OPTIMIZE_QUAD + )) { ImageInfo croppedInfo = cropped.imageInfo(); System.out.println("Cropped WxH: " + croppedInfo.getWidth() + "x" + croppedInfo.getHeight()); } diff --git a/examples/java/src/main/java/io/scanbot/sdk/utils/ExampleUsage.java b/examples/java/src/main/java/io/scanbot/sdk/utils/ExampleUsage.java index c191403..6471268 100644 --- a/examples/java/src/main/java/io/scanbot/sdk/utils/ExampleUsage.java +++ b/examples/java/src/main/java/io/scanbot/sdk/utils/ExampleUsage.java @@ -9,13 +9,13 @@ public static void print() { System.out.println("or"); System.out.println(" ./gradlew run --args='scan --file [--license ]'"); System.out.println("or"); - System.out.println(" ./gradlew run --args='analyze --resource --save [--license ]'"); + System.out.println(" ./gradlew run --args='analyze --resource [--save ] [--license ]'"); System.out.println("or"); - System.out.println(" ./gradlew run --args='analyze --file --save [--license ]'"); + System.out.println(" ./gradlew run --args='analyze --file [--save ] [--license ]'"); System.out.println("or"); - System.out.println(" ./gradlew run --args='enhance --resource [--license ]'"); + System.out.println(" ./gradlew run --args='enhance --resource [--save ] [--mask ] [--mask-resource ] [--license ]'"); System.out.println("or"); - System.out.println(" ./gradlew run --args='enhance --file [--license ]'"); + System.out.println(" ./gradlew run --args='enhance --file [--save ] [--mask ] [--mask-resource ] [--license ]'"); System.out.println(); System.out.println(" ./gradlew run --args='parse --text \"\" [--license ]'"); System.out.println(); @@ -26,20 +26,22 @@ public static void print() { System.out.println(" analyze_multi_page | crop_analyze"); System.out.println(); System.out.println("Available enhance commands:"); - System.out.println(" document"); + System.out.println(" straighten_document | cleanup_document"); System.out.println(); System.out.println("Available parse commands:"); System.out.println(" mrz | barcode_doc"); System.out.println(); System.out.println("Note:"); - System.out.println(" The --save argument is optional and only used with analyze/crop_analyze."); + System.out.println(" The --save argument is optional and used with analyze/crop_analyze and enhance/cleanup_document."); + System.out.println(" The --mask or --mask-resource argument is required for enhance/cleanup_document."); System.out.println(" The --license argument is optional. If not provided, the program will use placeholder variable ."); System.out.println(); System.out.println("Examples:"); System.out.println(" ./gradlew run --args='scan barcode --file images/example.jpg --license '"); System.out.println(" ./gradlew run --args='analyze analyze_multi_page --resource files/doc.pdf --license '"); System.out.println(" ./gradlew run --args='analyze crop_analyze --file images/doc.jpg --save out/crop.jpg --license '"); - System.out.println(" ./gradlew run --args='enhance document --file images/doc.jpg --license '"); + System.out.println(" ./gradlew run --args='enhance straighten_document --file images/doc.jpg --license '"); + System.out.println(" ./gradlew run --args='enhance cleanup_document --file ../../test-scripts/test-images/highlighted.png --mask ../../test-scripts/test-images/highlighted_mask_001.png --save out/cleaned.jpg --license '"); System.out.println(" ./gradlew run --args='parse mrz --text \"P'"); System.out.println(); } diff --git a/examples/nodejs/README.md b/examples/nodejs/README.md index 6d90c90..00f92d0 100644 --- a/examples/nodejs/README.md +++ b/examples/nodejs/README.md @@ -20,7 +20,7 @@ The example supports four modes: **scan**, **analyze**, **enhance**, and **parse ```bash npx ts-node src/index.ts scan --file [--license ] npx ts-node src/index.ts analyze --file [--save ] [--license ] -npx ts-node src/index.ts enhance --file [--license ] +npx ts-node src/index.ts enhance --file [--save ] [--mask ] [--license ] npx ts-node src/index.ts parse --text "" [--license ] ``` @@ -29,7 +29,8 @@ npx ts-node src/index.ts parse --text "" [--license ] npx ts-node src/index.ts scan barcode --file images/example.jpg --license npx ts-node src/index.ts analyze analyze_multi_page --file files/doc.pdf --license npx ts-node src/index.ts analyze crop_analyze --file images/doc.jpg --save out/crop.jpg --license -npx ts-node src/index.ts enhance document --file images/doc.jpg --license +npx ts-node src/index.ts enhance straighten_document --file images/doc.jpg --license +npx ts-node src/index.ts enhance cleanup_document --file ../../test-scripts/test-images/highlighted.png --mask ../../test-scripts/test-images/highlighted_mask_001.png --save out/cleaned.jpg --license npx ts-node src/index.ts parse mrz --text "P ``` diff --git a/examples/nodejs/package-lock.json b/examples/nodejs/package-lock.json index d48279c..d182673 100644 --- a/examples/nodejs/package-lock.json +++ b/examples/nodejs/package-lock.json @@ -9,7 +9,7 @@ "version": "1.0.0", "license": "ISC", "dependencies": { - "scanbotsdk": "https://github.com/doo/scanbot-sdk-example-linux/releases/download/standalone-sdk%2Fv9.0.0/nodejs-scanbotsdk-9.0.0.tgz" + "scanbotsdk": "https://github.com/doo/scanbot-sdk-example-linux/releases/download/standalone-sdk%2Fv0.1000.4/nodejs-scanbotsdk-0.1000.4.tgz" }, "devDependencies": { "@types/node": "^24.3.0", @@ -154,9 +154,9 @@ "license": "ISC" }, "node_modules/scanbotsdk": { - "version": "9.0.0", - "resolved": "https://github.com/doo/scanbot-sdk-example-linux/releases/download/standalone-sdk%2Fv9.0.0/nodejs-scanbotsdk-9.0.0.tgz", - "integrity": "sha512-aeyz2mSy7X9GY1EVoLFZnNIUTZhgRsjVuJVHsN+XLMatTa/Ifvxyf3gXUkw27SK2c32aesZnDSJfwz3NH3ruTQ==", + "version": "0.1000.4", + "resolved": "https://github.com/doo/scanbot-sdk-example-linux/releases/download/standalone-sdk%2Fv0.1000.4/nodejs-scanbotsdk-0.1000.4.tgz", + "integrity": "sha512-ssPoOUqNE+mC/ALfG6UDCZ+daEnfuXDVnBt5y4V/lc/Yl+9Jeu3EW9/m2RvwTa+dokj5+RQhwqyPxQk3Nl9u+A==", "hasInstallScript": true, "license": "Commercial", "os": [ diff --git a/examples/nodejs/package.json b/examples/nodejs/package.json index 309e43d..107aabf 100644 --- a/examples/nodejs/package.json +++ b/examples/nodejs/package.json @@ -15,6 +15,6 @@ "typescript": "^5.9.2" }, "dependencies": { - "scanbotsdk": "https://github.com/doo/scanbot-sdk-example-linux/releases/download/standalone-sdk%2Fv9.0.0/nodejs-scanbotsdk-9.0.0.tgz" + "scanbotsdk": "https://github.com/doo/scanbot-sdk-example-linux/releases/download/standalone-sdk%2Fv0.1000.4/nodejs-scanbotsdk-0.1000.4.tgz" } } diff --git a/examples/nodejs/src/index.ts b/examples/nodejs/src/index.ts index 62bdb6d..676b5d4 100644 --- a/examples/nodejs/src/index.ts +++ b/examples/nodejs/src/index.ts @@ -16,7 +16,8 @@ import { MrzParserSnippet } from "./snippets/datacapture/mrz-parser"; import { ParseBarcodeDocumentSnippet } from "./snippets/barcode/parse-barcode-document"; import { AnalyzeMultiPageSnippet } from "./snippets/document/analyze-multipage"; import { CropAndAnalyzeSnippet } from "./snippets/document/crop-analyze"; -import { DocumentEnhancerSnippet } from "./snippets/enhancer/document-enhancer"; +import { DocumentCleanupSnippet } from "./snippets/document/document-cleanup"; +import { DocumentStraightenerSnippet } from "./snippets/document/document-straightener"; async function awaitPromise(promise: Promise, maxAwaitTimeMs: number = 60 * 1000): Promise { const timer = setTimeout(() => { @@ -40,6 +41,7 @@ async function main(): Promise { const file = flags["--file"] as string | undefined; const save = flags["--save"] as string | undefined; + const mask = flags["--mask"] as string | undefined; const text = flags["--text"] as string | undefined; const licenseFlag = flags["--license"] as string | undefined; @@ -97,10 +99,16 @@ async function main(): Promise { case "enhance": { if (!file) { printUsage(); return; } - const image = await ScanbotSDK.ImageRef.fromPath(file); - switch (subcommand) { - case "document": await DocumentEnhancerSnippet.run(image); break; + case "straighten_document": { + const image = await ScanbotSDK.ImageRef.fromPath(file); + await DocumentStraightenerSnippet.run(image); + break; + } + case "cleanup_document": + if (!mask) { printUsage(); return; } + await DocumentCleanupSnippet.run(file, mask, save); + break; default: printUsage(); } break; diff --git a/examples/nodejs/src/snippets/document/document-cleanup.ts b/examples/nodejs/src/snippets/document/document-cleanup.ts new file mode 100644 index 0000000..e798e9e --- /dev/null +++ b/examples/nodejs/src/snippets/document/document-cleanup.ts @@ -0,0 +1,26 @@ +import * as ScanbotSDK from "scanbotsdk"; + +export class DocumentCleanupSnippet { + public static async run(filePath: string, maskPath: string, savePath?: string): Promise { + await using image = await ScanbotSDK.ImageRef.fromPath(filePath); + await using mask = await ScanbotSDK.ImageRef.fromPath(maskPath); + await using cleanup = await ScanbotSDK.DocumentCleanup.create( + image, + new ScanbotSDK.DocumentCleanupConfiguration() + ); + await using result = await cleanup.run(mask); + + console.log("Document cleanup status: " + result.status); + + const originalInfo = await image.imageInfo(); + const cleanedInfo = await result.image.imageInfo(); + + console.log(`Original WxH: ${originalInfo.width}x${originalInfo.height}`); + console.log(`Cleaned WxH: ${cleanedInfo.width}x${cleanedInfo.height}`); + + if (savePath) { + await result.image.saveImage(savePath, new ScanbotSDK.SaveImageOptions()); + console.log("Saved cleaned image to: " + savePath); + } + } +} diff --git a/examples/nodejs/src/snippets/enhancer/document-enhancer.ts b/examples/nodejs/src/snippets/document/document-straightener.ts similarity index 72% rename from examples/nodejs/src/snippets/enhancer/document-enhancer.ts rename to examples/nodejs/src/snippets/document/document-straightener.ts index fddebcc..ed8a4c5 100644 --- a/examples/nodejs/src/snippets/enhancer/document-enhancer.ts +++ b/examples/nodejs/src/snippets/document/document-straightener.ts @@ -1,7 +1,7 @@ import * as ScanbotSDK from "scanbotsdk"; import { AspectRatio } from "scanbotsdk"; -export class DocumentEnhancerSnippet { +export class DocumentStraightenerSnippet { public static async run(image: ScanbotSDK.ImageRef): Promise { var params = new ScanbotSDK.DocumentStraighteningParameters(); params.straighteningMode = "STRAIGHTEN"; @@ -12,10 +12,10 @@ export class DocumentEnhancerSnippet { new AspectRatio({ width: 3.0, height: 4.0 }) ]; - // `await using` ensures both enhancer and result are properly disposed + // `await using` ensures both straightener and result are properly disposed // when the scope ends, as they hold unmanaged resources. - await using enhancer = await ScanbotSDK.DocumentEnhancer.create(); - await using result = await enhancer.straighten(image, params); + await using straightener = await ScanbotSDK.DocumentStraightener.create(); + await using result = await straightener.run(image, params); // The straightened image can be accessed via result.straightenedImage and saved or further processed as needed. } diff --git a/examples/nodejs/src/snippets/utils/example-usage.ts b/examples/nodejs/src/snippets/utils/example-usage.ts index 760c1af..d568f67 100644 --- a/examples/nodejs/src/snippets/utils/example-usage.ts +++ b/examples/nodejs/src/snippets/utils/example-usage.ts @@ -2,16 +2,18 @@ export function printUsage(): void { console.log(` Usage: npx ts-node src/index.ts [--file ] [--save ] [--text ] [--license ] + npx ts-node src/index.ts enhance --file [--save ] [--mask ] [--license ] Categories & subcommands: scan analyze - enhance + enhance parse Flags: --file Path to an input image/file on disk --save Path to save outputs + --mask Path to cleanup mask image (required for enhance/cleanup_document) --text Text input for parsers --license Scanbot SDK license key (optional). If not provided, the placeholder variable "" is applied. @@ -20,7 +22,8 @@ Examples: npx ts-node src/index.ts scan barcode --file images/example.jpg --license npx ts-node src/index.ts analyze analyze_multi_page --file files/doc.pdf --license npx ts-node src/index.ts analyze crop_analyze --file images/doc.jpg --save out/crop.jpg --license - npx ts-node src/index.ts enhance document --file images/doc.jpg --license + npx ts-node src/index.ts enhance straighten_document --file images/doc.jpg --license + npx ts-node src/index.ts enhance cleanup_document --file ../../test-scripts/test-images/highlighted.png --mask ../../test-scripts/test-images/highlighted_mask_001.png --save out/cleaned.jpg --license npx ts-node src/index.ts parse mrz --text "P `); } diff --git a/examples/python/README.md b/examples/python/README.md index 0ebb88d..eabba85 100644 --- a/examples/python/README.md +++ b/examples/python/README.md @@ -1,33 +1,33 @@ -# Scanbot SDK – Python on Linux +# Scanbot SDK – Python on Linux/Windows ## NVidia Jetson > Requires **Jetpack 6.1**, **CUDA 12.6**, and **TensorRT 10.3** for GPU acceleration. ### 1. Install Python and OpenCV -```bash -sudo apt install -y python3-venv nvidia-opencv -``` + ```bash + sudo apt install -y python3-venv nvidia-opencv + ``` ### 2. (Optional) Install CUDA + TensorRT Make sure you are running a supported Jetpack version: -```bash -sudo apt install -y nvidia-l4t-cuda libnvinfer10 libnvinfer-plugin10 libnvonnxparsers10 -``` + ```bash + sudo apt install -y nvidia-l4t-cuda libnvinfer10 libnvinfer-plugin10 libnvonnxparsers10 + ``` ### 3. Create and activate a virtual environment -```bash -python3 -m venv .env --system-site-packages -source .env/bin/activate -pip install --upgrade pip setuptools wheel -``` + ```bash + python3 -m venv .env --system-site-packages + source .env/bin/activate + pip install --upgrade pip setuptools wheel + ``` ### 3. Install the Scanbot SDK Replace `` with the actual version number of the SDK you want to install. -```bash -export SCANBOT_SDK_VERSION= -``` + ```bash + export SCANBOT_SDK_VERSION= + ``` * **On ARM64 (Raspberry Pi, Jetson Nano, etc.):** ```bash @@ -40,42 +40,42 @@ export SCANBOT_SDK_VERSION= ``` ### 5. Verify installation -```bash -python -c "import scanbotsdk" -``` + ```bash + python -c "import scanbotsdk" + ``` ### ⚡ Performance notes (Jetson) To avoid throttling, set max GPU/CPU/memory clocks: -```bash -sudo jetson_clocks --store -sudo jetson_clocks -``` + ```bash + sudo jetson_clocks --store + sudo jetson_clocks + ``` Restore defaults later: -```bash -sudo jetson_clocks --restore -``` + ```bash + sudo jetson_clocks --restore + ``` ## Raspberry Pi OS, Ubuntu, Debian ### 1. Install Python and OpenCV -```bash -sudo apt install -y python3-venv python3-opencv -``` + ```bash + sudo apt install -y python3-venv python3-opencv + ``` ### 2. Create and activate a virtual environment -```bash -python3 -m venv .env --system-site-packages -source .env/bin/activate -pip install --upgrade pip setuptools wheel -``` + ```bash + python3 -m venv .env --system-site-packages + source .env/bin/activate + pip install --upgrade pip setuptools wheel + ``` ### 3. Install the Scanbot SDK Replace `` with the actual version number of the SDK you want to install. -```bash -export SCANBOT_SDK_VERSION= -``` + ```bash + export SCANBOT_SDK_VERSION= + ``` * **On ARM64 (Raspberry Pi, Jetson Nano, etc.):** ```bash @@ -88,16 +88,55 @@ export SCANBOT_SDK_VERSION= ``` ### 4. Verify installation -```bash -python -c "import scanbotsdk" -``` + ```bash + python -c "import scanbotsdk" + ``` + +## Windows + +### 1. Prerequisites +* x86/x86_64 CPU +* Python 3.6+ (32/64-bit) +* PowerShell +* OpenCV (only for examples) + +The snippets below are written for PowerShell, not cmd. + +### 2. Create and activate a virtual environment: + ```powershell + python -m venv .env --system-site-packages + . .\.env\Scripts\Activate.ps1 + python -m pip install --upgrade pip setuptools wheel + python -m pip install opencv-python + ``` + +### 3. Install the Scanbot SDK +Replace `` with the actual version number of the SDK you want to install. + ```powershell + $SCANBOT_SDK_VERSION = "" + ``` + +* **Python x86_64 (64-bit):** + ```powershell + pip install https://github.com/doo/scanbot-sdk-example-linux/releases/download/standalone-sdk%2Fv${SCANBOT_SDK_VERSION}/scanbotsdk-${SCANBOT_SDK_VERSION}-py3-none-win_amd64.whl + ``` + +* **Python x86 (32-bit):** + ```powershell + pip install https://github.com/doo/scanbot-sdk-example-linux/releases/download/standalone-sdk%2Fv${SCANBOT_SDK_VERSION}/scanbotsdk-${SCANBOT_SDK_VERSION}-py3-none-win32.whl + ``` + +### 4. Verify installation + ```powershell + python -c "import scanbotsdk" + ``` ## Usage The example supports five modes: **scan**, **analyze**, **enhance**, **parse**, and **live**. ```bash python main.py scan --file [--license ] python main.py analyze --file [--save ] [--license ] -python main.py enhance --file [--license ] +python main.py enhance --file [--save ] [--mask ] [--license ] python main.py parse --text "" [--license ] python main.py live --device "" [--license ] [--preview] [--use_tensorrt] ``` @@ -107,7 +146,8 @@ python main.py live --device "" [--license ] [-- python main.py scan barcode --file images/example.jpg --license python main.py analyze analyze_multi_page --file files/doc.pdf --license python main.py analyze crop_analyze --file images/doc.jpg --save out/crop.jpg --license -python main.py enhance document --file images/doc.jpg --license +python main.py enhance straighten_document --file images/doc.jpg --license +python main.py enhance cleanup_document --file ../../test-scripts/test-images/highlighted.png --mask ../../test-scripts/test-images/highlighted_mask_001.png --save out/cleaned.jpg --license python main.py parse mrz --text "P python main.py live barcode --device "0" --license ``` diff --git a/examples/python/main.py b/examples/python/main.py index 3b198a9..30ed29b 100644 --- a/examples/python/main.py +++ b/examples/python/main.py @@ -1,9 +1,10 @@ import sys import scanbotsdk -from snippets.enhancer.document_enhancer import enhance_document +from snippets.document.document_straightener import straighten_document from snippets.document.analyze_multi_page import analyze_multi_page from snippets.document.crop_and_analyze import crop_and_analyze +from snippets.document.document_cleanup import cleanup_document from snippets.barcode.barcode_document_parser import parse_barcode_document from snippets.datacapture.mrz_parser import parse_mrz from snippets.datacapture.vin import scan_vin @@ -47,6 +48,7 @@ def main(): file_path = flags.get("--file") save_path = flags.get("--save") + mask_path = flags.get("--mask") text_input = flags.get("--text") device_input = flags.get("--device") # live only show_preview = "--preview" in flags # live only @@ -69,9 +71,13 @@ def main(): elif category == "enhance": if not file_path: print_usage(); return - with create_image_ref(file_path) as image: - if subcommand == "document": enhance_document(image) - else: print_usage() + if subcommand == "straighten_document": + with create_image_ref(file_path) as image: + straighten_document(image) + elif subcommand == "cleanup_document": + if not mask_path: print_usage(); return + cleanup_document(file_path, mask_path, save_path) + else: print_usage() elif category == "analyze": if not file_path: print_usage(); return diff --git a/examples/python/snippets/document/document_cleanup.py b/examples/python/snippets/document/document_cleanup.py new file mode 100644 index 0000000..a0ce48d --- /dev/null +++ b/examples/python/snippets/document/document_cleanup.py @@ -0,0 +1,26 @@ +import os +from typing import Optional + +from scanbotsdk import * +from utils import create_image_ref + + +def cleanup_document(image_path: str, mask_path: str, save_path: Optional[str] = None): + with create_image_ref(image_path) as image, create_image_ref(mask_path) as mask: + cleanup = DocumentCleanup( + image=image, + configuration=DocumentCleanupConfiguration() + ) + result = cleanup.run(mask=mask) + + print(f"Document cleanup status: {result.status.name}") + + if result.status == DocumentCleanupStatus.OK: + original_info = image.info() + cleaned_info = result.image.info() + print(f"Original WxH: {original_info.width}x{original_info.height}") + print(f"Cleaned WxH: {cleaned_info.width}x{cleaned_info.height}") + + if save_path: + result.image.save_image(save_path, SaveImageOptions()) + print(f"Saved cleaned image to: {os.path.abspath(save_path)}") diff --git a/examples/python/snippets/enhancer/document_enhancer.py b/examples/python/snippets/document/document_straightener.py similarity index 72% rename from examples/python/snippets/enhancer/document_enhancer.py rename to examples/python/snippets/document/document_straightener.py index 1f51408..bfbc0d2 100644 --- a/examples/python/snippets/enhancer/document_enhancer.py +++ b/examples/python/snippets/document/document_straightener.py @@ -1,6 +1,6 @@ from scanbotsdk import * -def enhance_document(image: ImageRef): +def straighten_document(image: ImageRef): params = DocumentStraighteningParameters() params.straightening_mode = DocumentStraighteningMode.STRAIGHTEN params.aspect_ratios = [ @@ -10,7 +10,7 @@ def enhance_document(image: ImageRef): AspectRatio(width=3.0, height=4.0) ] - enhancer = DocumentEnhancer() - result: DocumentStraighteningResult = enhancer.straighten(image=image, parameters=params) + straightener = DocumentStraightener() + result: DocumentStraighteningResult = straightener.run(image=image, parameters=params) # The straightened image can be accessed via result.straightened_image and saved or further processed as needed. diff --git a/examples/python/snippets/live/camera.py b/examples/python/snippets/live/camera.py index 78f18fe..f59af00 100644 --- a/examples/python/snippets/live/camera.py +++ b/examples/python/snippets/live/camera.py @@ -1,8 +1,12 @@ +import sys +from typing import Tuple + import cv2 as cv -# Default camera settings (resolution and framerate) + WIDTH, HEIGHT, FPS = 1280, 720, 30 + def _gst_pipeline(device: str) -> str: if device == "jetson_csi": return ( @@ -11,26 +15,76 @@ def _gst_pipeline(device: str) -> str: f"framerate=(fraction){FPS}/1 ! " "nvvidconv flip-method=0 ! " "video/x-raw, format=(string)BGRx ! " - "videoconvert ! video/x-raw, format=(string)BGR ! appsink drop=1" + "videoconvert ! " + "video/x-raw, format=(string)BGR ! " + "appsink drop=1" ) + if device == "libcamera": return ( - "libcamerasrc ! video/x-raw, format=BGR, " + "libcamerasrc ! " + "video/x-raw, format=BGR, " f"width=(int){WIDTH}, height=(int){HEIGHT}, " - f"framerate=(fraction){FPS}/1 ! appsink" + f"framerate=(fraction){FPS}/1 ! " + "appsink drop=1" ) - raise ValueError(f"Invalid device for GStreamer: {device!r}") + + raise ValueError(f"Invalid GStreamer device: {device!r}") + + +def _backends_for_index() -> Tuple[int, ...]: + if sys.platform.startswith("win"): + return (cv.CAP_MSMF, cv.CAP_DSHOW) + + if sys.platform == "darwin": + return (cv.CAP_AVFOUNDATION,) + + if sys.platform.startswith("linux"): + return (cv.CAP_V4L2,) + + return (cv.CAP_ANY,) + + +def _configure_camera(cap: cv.VideoCapture) -> None: + properties = ( + (cv.CAP_PROP_FRAME_WIDTH, WIDTH), + (cv.CAP_PROP_FRAME_HEIGHT, HEIGHT), + (cv.CAP_PROP_FPS, FPS), + ) + + for prop, value in properties: + cap.set(prop, value) + + +def _open_index(index: int) -> cv.VideoCapture: + for backend in _backends_for_index(): + cap = cv.VideoCapture(index, backend) + + if not cap.isOpened(): + cap.release() + continue + + _configure_camera(cap) + return cap + + raise RuntimeError(f"Cannot open camera index {index}") def open_camera(device: str) -> cv.VideoCapture: - """Open V4L2 (numeric index) or GStreamer ('jetson_csi' / 'libcamera').""" + """Open a numeric camera index or a supported GStreamer pipeline.""" + try: - cap = cv.VideoCapture(int(device), cv.CAP_V4L2) - cap.set(cv.CAP_PROP_FRAME_WIDTH, WIDTH) - cap.set(cv.CAP_PROP_FRAME_HEIGHT, HEIGHT) - cap.set(cv.CAP_PROP_FPS, FPS) + index = int(device) except ValueError: - cap = cv.VideoCapture(_gst_pipeline(device), cv.CAP_GSTREAMER) - if not cap.isOpened(): - raise RuntimeError("Cannot open camera") - return cap + pipeline = _gst_pipeline(device) + cap = cv.VideoCapture(pipeline, cv.CAP_GSTREAMER) + + if not cap.isOpened(): + cap.release() + raise RuntimeError( + f"Cannot open GStreamer pipeline for {device!r}" + ) + + return cap + + return _open_index(index) \ No newline at end of file diff --git a/examples/python/utils.py b/examples/python/utils.py index f33c743..e5dff9f 100644 --- a/examples/python/utils.py +++ b/examples/python/utils.py @@ -54,8 +54,8 @@ def print_usage(): print("Scanbot SDK Example\n") print("Usage:") print(" python main.py scan --file [--license ]") - print(" python main.py analyze --file --save [--license ]") - print(" python main.py enhance --file [--license ]") + print(" python main.py analyze --file [--save ] [--license ]") + print(" python main.py enhance --file [--save ] [--mask ] [--license ]") print(" python main.py parse --text \"\" [--license ]") print(" python main.py live --device [--license ] --preview --use_tensorrt\n") @@ -68,14 +68,15 @@ def print_usage(): print("Available analyze commands:") print(" analyze_multi_page | crop_analyze\n") print("Available enhance commands:") - print(" document \n") + print(" straighten_document | cleanup_document\n") print("Available parse commands:") print(" mrz | barcode_doc\n") print("Available live commands:") print(" barcode | document\n") print("Note:") - print(" --save is optional, only used with analyze/crop_analyze.") + print(" --save is optional for analyze/crop_analyze and enhance/cleanup_document.") + print(" --mask is required for enhance/cleanup_document.") print(" --license is optional, default is \"\".") print(" --device is required for live command (e.g. libcamera or jetson_csi).\n") print(" --use_tensorrt is optional for live command to enable TensorRtAccelerator") @@ -84,6 +85,8 @@ def print_usage(): print(" python main.py scan barcode --file images/example.jpg --license ") print(" python main.py analyze analyze_multi_page --file files/doc.pdf --license ") print(" python main.py analyze crop_analyze --file images/doc.jpg --save out/crop.jpg --license ") + print(" python main.py enhance straighten_document --file images/doc.jpg --license ") + print(" python main.py enhance cleanup_document --file ../../test-scripts/test-images/highlighted.png --mask ../../test-scripts/test-images/highlighted_mask_001.png --save out/cleaned.jpg --license ") print(" python main.py parse mrz --text \"P") print(" python main.py live barcode --device jetson_csi --license ") print() diff --git a/test-scripts/README.md b/test-scripts/README.md index dcb2569..57abf1c 100644 --- a/test-scripts/README.md +++ b/test-scripts/README.md @@ -15,11 +15,18 @@ These test scripts validate the Scanbot SDK integration across all supported lan ``` test-scripts/ -├── test-python.sh # Python SDK tests -├── test-java.sh # Java SDK tests -├── test-nodejs.sh # Node.js SDK tests -├── test-c.sh # C SDK tests -├── run-all-tests.sh # Run all tests +├── linux/ +│ ├── test-python.sh # Python SDK tests +│ ├── test-java.sh # Java SDK tests +│ ├── test-nodejs.sh # Node.js SDK tests +│ ├── test-c.sh # C SDK tests +│ ├── run-all-tests.sh # Run all tests +│ └── Dockerfile # Linux CI/test image +├── windows/ +│ ├── test-python.ps1 # Python SDK tests +│ ├── test-c.ps1 # C SDK tests +│ ├── run-all-tests.ps1 # Run all tests +│ └── Dockerfile # Windows CI/test image └── test-images/ # Test image files ``` @@ -29,13 +36,14 @@ test-scripts/ ```bash export SCANBOT_LICENSE="your-license-key-here" -export SDK_VERSION=9.0.0 +export SDK_VERSION=0.1000.4 ``` ### 2. Build Test Container ```bash docker build \ + -f test-scripts/linux/Dockerfile \ --build-arg SDK_VERSION=$SDK_VERSION \ --build-arg ARCH=linux-aarch64 \ --build-arg SCANBOT_LICENSE=$SCANBOT_LICENSE \ diff --git a/Dockerfile b/test-scripts/linux/Dockerfile similarity index 99% rename from Dockerfile rename to test-scripts/linux/Dockerfile index a64b5b0..7ea0c50 100644 --- a/Dockerfile +++ b/test-scripts/linux/Dockerfile @@ -106,7 +106,7 @@ RUN echo "Installing Java and C SDKs for architecture: ${ARCH}" && \ echo "All SDKs installed successfully" # Copy test scripts -COPY test-scripts/ /tests/ +COPY test-scripts/linux/ /tests/ RUN chmod +x /tests/*.sh # SDK Verification Stage diff --git a/test-scripts/run-all-tests.sh b/test-scripts/linux/run-all-tests.sh similarity index 100% rename from test-scripts/run-all-tests.sh rename to test-scripts/linux/run-all-tests.sh diff --git a/test-scripts/test-c.sh b/test-scripts/linux/test-c.sh similarity index 79% rename from test-scripts/test-c.sh rename to test-scripts/linux/test-c.sh index 41b92ad..9760d60 100755 --- a/test-scripts/test-c.sh +++ b/test-scripts/linux/test-c.sh @@ -46,9 +46,11 @@ commands=( "scan ocr --file ../../test-scripts/test-images/Document.jpeg --license \"${SCANBOT_LICENSE}\"" "scan text_pattern --file ../../test-scripts/test-images/Document.jpeg --license \"${SCANBOT_LICENSE}\"" "scan vin --file ../../test-scripts/test-images/VIN.jpeg --license \"${SCANBOT_LICENSE}\"" - "enhance document --file ../../test-scripts/test-images/Document.jpeg --license \"${SCANBOT_LICENSE}\"" - "analyze analyze_multi_page --file ../../test-scripts/test-images/multi_page_document.pdf --license \"${SCANBOT_LICENSE}\"" - "analyze crop_analyze --file ../../test-scripts/test-images/Document.jpeg --license \"${SCANBOT_LICENSE}\"" + "enhance straighten_document --file ../../test-scripts/test-images/Document.jpeg --license \"${SCANBOT_LICENSE}\"" + "analyze analyze_multi_page --file ../../test-scripts/test-images/multi_page_document.pdf --save /tmp/out.pdf --license \"${SCANBOT_LICENSE}\"" + "analyze crop_analyze --file ../../test-scripts/test-images/Document.jpeg --save /tmp/crop.jpeg --license \"${SCANBOT_LICENSE}\"" + "enhance cleanup_document --file ../../test-scripts/test-images/highlighted.png --mask ../../test-scripts/test-images/highlighted_mask_001.png --save /tmp/highlighted_cleaned.png --license \"${SCANBOT_LICENSE}\"" + "enhance cleanup_document --file ../../test-scripts/test-images/finger_corner.jpeg --mask ../../test-scripts/test-images/finger_corner_mask_001.png --save /tmp/finger_corner_cleaned.png --license \"${SCANBOT_LICENSE}\"" # TODO: Fix C SDK parse test,which currently returns success 0 only in tests "parse mrz --text \"P