Deprecation warning

Please note that this is outdated documentation for an older release of the Scandit Barcode Scanner SDK.

We are deprecating the 5.x API on all platforms (except Linux). Release 5.19 in April 2021 will be our final. Applications running 5.x will continue to work, and we will continue to release critical bug fixes and security patches only, for one year. We encourage you to migrate to 6.x and take advantage of our latest / advanced features and improved performance.

You'll find the updated documentation at: Data Capture SDK Documentation for Android

ScanditNativeBarcodeScannerDemo.c

Detecting Barcodes in Images

This example uses the Scandit SDK to detect barcodes in images

It illustrates the following aspects:

  • Loading of images from disk using the ImageMagick library.
  • Setting up and initializing a barcode scanner to scan EAN13, UPCA and QR codes.
  • Handling of the recognized barcode results.
  • Closing of the recognition context and barcode scanner.
#include <dirent.h>
#include <stdio.h>
#include <string.h>
#include <assert.h>
#include <wand/magick-wand.h>
// Please insert your app key here:
#define SCANDIT_SDK_APP_KEY "--- INSERT YOUR APP KEY HERE ---"
static char const * const ENABLED_FILE_EXTENSIONS[] = {
"png",
"jpg",
NULL
};
typedef struct InputImage {
char const *file_name;
struct InputImage const *next;
} InputImage;
static int has_valid_extension(char const *file_name)
{
char const * const *extension = ENABLED_FILE_EXTENSIONS;
for (; *extension != NULL; ++extension) {
const size_t file_name_length = strlen(file_name);
const size_t extension_length = strlen(*extension);
char const * const file_extension =
file_name + (file_name_length - extension_length);
if (file_name_length >= extension_length &&
strcmp(file_extension, *extension) == 0) {
return SC_TRUE;
}
}
return SC_FALSE;
}
static InputImage *push_if_valid_image(char const * filename,
InputImage *container) {
if (has_valid_extension(filename) == SC_TRUE) {
InputImage *new_image = malloc(sizeof(InputImage));
const size_t target_size = strlen(filename) + 1;
new_image->file_name = malloc(target_size);
strncpy((char*)new_image->file_name, filename, target_size);
new_image->next = container;
container = new_image;
}
return container;
}
InputImage const *get_input_files(int argc, char const *argv[]) {
InputImage *ret = NULL;
// We skip fist argument
for (int arg_idx = 1; arg_idx < argc; ++arg_idx) {
char const * const current_arg = argv[arg_idx];
DIR *dir;
struct dirent *ent;
if ((dir = opendir(current_arg)) != NULL) {
// We have a directory
while ((ent = readdir (dir)) != NULL) {
char *combined_name = malloc(sizeof(current_arg) +
sizeof(ent->d_name) + 2);
combined_name[0] = '\0';
strcat(combined_name, current_arg);
strcat(combined_name, "/");
strcat(combined_name, ent->d_name);
ret = push_if_valid_image(combined_name, ret);
}
closedir (dir);
} else {
// We have a file
ret = push_if_valid_image(current_arg, ret);
}
}
return ret;
}
static ScBool load_image(const char* image_name, uint8_t** data,
uint64_t* width, uint64_t *height) {
MagickWand *image = NULL;
MagickWandGenesis();
image = NewMagickWand();
if (MagickReadImage(image, image_name) == MagickFalse) {
DestroyMagickWand(image);
MagickWandTerminus();
return SC_FALSE;
}
// Convert image to RGB, so we can access the pixel data directly.
assert(MagickSetImageFormat(image, "RGB"));
assert(MagickSetImageColorspace(image, RGBColorspace));
assert(MagickSetImageType(image, TrueColorType));
assert(MagickSetImageDepth(image, 8));
*width = MagickGetImageWidth(image);
*height = MagickGetImageHeight(image);
size_t blob_size = 0;
uint8_t* image_data = MagickGetImageBlob(image, &blob_size);
printf("image size: %dx%d (%d bytes)\n", (int)*width, (int)*height,
(int)blob_size);
*data = malloc(blob_size);
memcpy(*data, image_data, blob_size);
MagickRelinquishMemory(image_data);
DestroyMagickWand(image);
MagickWandTerminus();
return SC_TRUE;
}
int main(int argc, const char *argv[])
{
if (argc < 2) {
printf("Please provide paths to image files or directories as arguments.\n");
return -1;
}
printf("Scandit SDK Version: %s\n", SC_VERSION_STRING);
int return_code = 0;
ScRecognitionContext *context = NULL;
ScBarcodeScanner *scanner = NULL;
ScImageDescription *image_descr = NULL;
ScBarcodeScannerSettings *settings = NULL;
uint8_t *image_data = NULL;
InputImage const * const images = get_input_files(argc, argv);
// Create a recognition context. Files created by the recognition context and the
// attached scanners should be written to /tmp. You can use any other writable data
// directory in your application.
context = sc_recognition_context_new(SCANDIT_SDK_APP_KEY, "/tmp", NULL);
if (context == NULL) {
printf("Could not initialize context.\n");
return_code = -1;
goto cleanup;
}
image_descr = sc_image_description_new();
if (image_descr == NULL) {
printf("Could not initialize image description.\n");
return_code = -1;
goto cleanup;
}
// The barcode scanner is configured by setting the appropriate properties on an
// "barcode scanner settings" instance. This settings object is passed to the barcode
// scanner when it is constructed. We start with the default settings object and enable
// only the symbologies we need. For the purpose of this demo, we would like to scan
// EAN13/UPCA and QR codes
if (settings == NULL) {
printf("Could not initialize settings.\n");
return_code = -1;
goto cleanup;
}
// Set to false to only look for horizontal and centered codes.
const ScBool use_full_image_localization = SC_TRUE;
if (use_full_image_localization == SC_TRUE) {
// By setting the code location constraints to hint and code direction to none, we tell
// the engine to run the full-image localization for every frame.
} else {
// Turn off full-image localization and only run scanline along the
// direction of the code direction hint for every frame.
}
// The barcode scanner allows to prevent codes from getting scanned again in
// a certain time interval (e.g., 500ms). The default setting is 0 what
// effectively disables this duplicate filtering.
//sc_barcode_scanner_settings_set_code_duplicate_filter(settings, 500);
// Create a barcode scanner for our context and settings.
scanner = sc_barcode_scanner_new_with_settings(context, settings);
if (scanner == NULL) {
printf("Could not initialize scanner.\n");
return_code = -1;
goto cleanup;
}
// Wait for the initialization of the barcode scanner. We could omit this call
// and start scanning immediately, but there is no guarantee that the barcode scanner
// operates at full capacity
printf("barcode scanner setup failed.\n");
return_code = -1;
goto cleanup;
}
for (InputImage const *current_image = images; current_image != NULL;
current_image = current_image->next) {
// Load the image from disc.
uint64_t image_width;
uint64_t image_height;
if (load_image(current_image->file_name, &image_data, &image_width,
&image_height) == SC_FALSE) {
printf("Failed to load image '%s'.\n", current_image->file_name);
return -1;
}
// Fill the image description for our loaded image.
const uint32_t image_memory_size = image_width * image_height * 3;
sc_image_description_set_width(image_descr, image_width);
sc_image_description_set_height(image_descr, image_height);
sc_image_description_set_memory_size(image_descr, image_memory_size);
// Signal to the context that a new sequence of frames starts. This call is mandatory,
// even if we are only going to process one image. Scanning will fail with
// SC_RECOGNITION_CONTEXT_STATUS_FRAME_SEQUENCE_NOT_STARTED otherwise.
image_data);
printf("Processing frame failed with error %d: '%s'\n", result.status,
return_code = -1;
goto cleanup;
}
// Signal to the context that the frame sequence is finished.
// Retrieve the barcode scanner object to get the list of codes that were recognized in
// the last frame.
// Get the list of codes that have been found in the last process frame call.
ScBarcodeArray * new_codes =
uint32_t num_codes = sc_barcode_array_get_size(new_codes);
if (num_codes == 0) {
printf("no barcodes or QR codes found\n");
}
for (uint32_t i = 0; i < num_codes; ++i) {
const ScBarcode * barcode = sc_barcode_array_get_item_at(new_codes, i);
ScSymbology symbology = sc_barcode_get_symbology(barcode);
const char *symbology_name = sc_symbology_to_string(symbology);
// For simplicity it is assumed that the barcode contains textual data, even
// though it is possible to encode binary data in QR codes that contain null-
// bytes at any position. For applications expecting binary data, use
// sc_byte_array_get_data_size() to determine the length of the returned data.
printf("barcode: symbology=%s, data='%s'\n", symbology_name, data.str);
}
free(image_data);
image_data = NULL;
}
cleanup:
// cleanup allocated data and objects. These functions all check for null values,
// so it's save to pass in null objects.
free(image_data);
for (InputImage const *current_image = images; current_image != NULL;) {
InputImage const *next_image = current_image->next;
free((char *)current_image->file_name);
free((char *)current_image);
current_image = next_image;
}
return return_code;
}