summaryrefslogtreecommitdiffstats
path: root/zbarcam
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-03-09 00:06:44 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-03-09 00:06:44 +0000
commit44cf8ec67278bd1ab6c7f83a9993f7a5686a9541 (patch)
tree5eec4b0d1a3f163d279c3c27c03324ba49fa235a /zbarcam
parentInitial commit. (diff)
downloadzbar-44cf8ec67278bd1ab6c7f83a9993f7a5686a9541.tar.xz
zbar-44cf8ec67278bd1ab6c7f83a9993f7a5686a9541.zip
Adding upstream version 0.23.93.upstream/0.23.93upstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'zbarcam')
-rw-r--r--zbarcam/Makefile.am.inc44
-rw-r--r--zbarcam/scan_video.c227
-rw-r--r--zbarcam/zbarcam-gtk.c231
-rw-r--r--zbarcam/zbarcam-qt.cpp1050
-rw-r--r--zbarcam/zbarcam.c375
-rw-r--r--zbarcam/zbarcam.rc30
6 files changed, 1957 insertions, 0 deletions
diff --git a/zbarcam/Makefile.am.inc b/zbarcam/Makefile.am.inc
new file mode 100644
index 0000000..df6794d
--- /dev/null
+++ b/zbarcam/Makefile.am.inc
@@ -0,0 +1,44 @@
+bin_PROGRAMS += zbarcam/zbarcam
+zbarcam_zbarcam_SOURCES = zbarcam/zbarcam.c
+zbarcam_zbarcam_LDADD = zbar/libzbar.la
+zbarcam_zbarcam_CPPFLAGS = $(AM_CPPFLAGS)
+# automake bug in "monolithic mode"?
+CLEANFILES += zbarcam/.libs/zbarcam zbarcam/moc_zbarcam_qt.h
+
+if HAVE_GTK
+if !WIN32
+bin_PROGRAMS += zbarcam/zbarcam-gtk
+zbarcam_zbarcam_gtk_SOURCES = zbarcam/zbarcam-gtk.c zbarcam/scan_video.c
+zbarcam_zbarcam_gtk_CPPFLAGS = $(GTK_CFLAGS) $(AM_CPPFLAGS)
+zbarcam_zbarcam_gtk_LDADD = $(GTK_LIBS) gtk/libzbargtk.la zbar/libzbar.la \
+ $(AM_LDADD)
+
+endif
+endif
+
+if HAVE_QT
+bin_PROGRAMS += zbarcam/zbarcam-qt
+
+zbarcam_zbarcam_qt_SOURCES = zbarcam/zbarcam-qt.cpp zbarcam/scan_video.c
+nodist_zbarcam_zbarcam_qt_SOURCES = zbarcam/moc_zbarcam_qt.h
+zbarcam_zbarcam_qt_CPPFLAGS = -Izbarcam $(QT_CFLAGS) $(AM_CPPFLAGS)
+zbarcam_zbarcam_qt_LDADD = $(QT_LIBS) qt/libzbarqt.la $(AM_LDADD)
+BUILT_SOURCES += $(nodist_zbarcam_zbarcam_qt_SOURCES)
+DISTCLEANFILES += $(nodist_zbarcam_zbarcam_qt_SOURCES) zbarcam/moc_zbarcam_qt.h
+
+
+zbarcam/moc_zbarcam_qt.h: zbarcam/zbarcam-qt.cpp
+ $(mkdir_p) zbarcam
+ $(MOC) -i $(zbarcam_zbarcam_qt_CPPFLAGS) $< -o $@
+endif
+
+
+if WIN32
+zbarcam_zbarcam_SOURCES += zbarcam/zbarcam.rc
+zbarcam_zbarcam_LDADD += zbarcam/zbarcam-rc.o @LTLIBINTL@
+
+if WITH_DIRECTSHOW
+zbarcam_zbarcam_CPPFLAGS += -DDIRECTSHOW
+endif
+
+endif
diff --git a/zbarcam/scan_video.c b/zbarcam/scan_video.c
new file mode 100644
index 0000000..c83e53e
--- /dev/null
+++ b/zbarcam/scan_video.c
@@ -0,0 +1,227 @@
+/*------------------------------------------------------------------------
+ * Copyright 2008-2009 (c) Jeff Brown <spadix@users.sourceforge.net>
+ *
+ * This file is part of the ZBar Bar Code Reader.
+ *
+ * The ZBar Bar Code Reader is free software; you can redistribute it
+ * and/or modify it under the terms of the GNU Lesser Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * The ZBar Bar Code Reader is distributed in the hope that it will be
+ * useful, but WITHOUT ANY WARRANTY; without even the implied warranty
+ * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser Public License
+ * along with the ZBar Bar Code Reader; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301 USA
+ *
+ * http://sourceforge.net/projects/zbar
+ *------------------------------------------------------------------------*/
+
+#include "config.h"
+
+#include <fcntl.h>
+#include <ftw.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include <linux/videodev2.h>
+
+#include <sys/ioctl.h>
+#include <sys/stat.h>
+#ifdef MAJOR_IN_SYSMACROS
+#include <sys/sysmacros.h>
+#endif
+typedef void(cb_t)(void *userdata, const char *device);
+
+struct devnodes {
+ char *fname;
+ int minor;
+ int is_valid;
+};
+
+static unsigned int n_devices = 0;
+static struct devnodes *devices = NULL;
+
+/*
+ * Sort order:
+ *
+ * - Valid devices comes first
+ * - Lowest minors comes first
+ *
+ * For devnode names, it sorts on this order:
+ * - custom udev given names
+ * - /dev/v4l/by-id/
+ * - /dev/v4l/by-path/
+ * - /dev/video
+ * - /dev/char/
+ *
+ * - Device name is sorted alphabetically if follows same pattern
+ */
+static int sort_devices(const void *__a, const void *__b)
+{
+ const struct devnodes *a = __a;
+ const struct devnodes *b = __b;
+ int val_a, val_b;
+
+ if (a->is_valid != b->is_valid)
+ return !a->is_valid - !b->is_valid;
+
+ if (a->minor != b->minor)
+ return a->minor - b->minor;
+
+ /* Ensure that /dev/video* devices will stay at the top */
+
+ if (strstr(a->fname, "by-id"))
+ val_a = 1;
+ if (strstr(a->fname, "by-path"))
+ val_a = 2;
+ else if (strstr(a->fname, "/dev/video"))
+ val_a = 3;
+ else if (strstr(a->fname, "char"))
+ val_a = 4;
+ else /* Customized names comes first */
+ val_a = 0;
+
+ if (strstr(b->fname, "by-id"))
+ val_b = 1;
+ if (strstr(b->fname, "by-path"))
+ val_b = 2;
+ else if (strstr(b->fname, "/dev/video"))
+ val_b = 3;
+ else if (strstr(b->fname, "char"))
+ val_b = 4;
+ else /* Customized names comes first */
+ val_b = 0;
+
+ if (val_a != val_b)
+ return val_a - val_b;
+
+ /* Finally, just use alphabetic order */
+ return strcmp(a->fname, b->fname);
+}
+
+static int handle_video_devs(const char *file, const struct stat *st, int flag)
+{
+ int dev_minor, first_device = -1, fd;
+ unsigned int i;
+ struct v4l2_capability vid_cap = { 0 };
+
+ /* Discard devices that can't be a videodev */
+ if (!S_ISCHR(st->st_mode) || major(st->st_rdev) != 81)
+ return 0;
+
+ dev_minor = minor(st->st_rdev);
+
+ /* check if it is an already existing device */
+ if (devices) {
+ for (i = 0; i < n_devices; i++) {
+ if (dev_minor == devices[i].minor) {
+ first_device = i;
+ break;
+ }
+ }
+ }
+
+ devices = realloc(devices, (n_devices + 1) * sizeof(struct devnodes));
+ if (!devices) {
+ perror("Can't allocate memory to store devices");
+ exit(1);
+ }
+ memset(&devices[n_devices], 0, sizeof(struct devnodes));
+
+ if (first_device < 0) {
+ fd = open(file, O_RDWR);
+ if (fd < 0) {
+ devices[n_devices].is_valid = 0;
+ } else {
+ if (ioctl(fd, VIDIOC_QUERYCAP, &vid_cap) == -1) {
+ devices[n_devices].is_valid = 0;
+ } else {
+#ifdef V4L2_CID_ALPHA_COMPONENT
+ /*
+ * device_caps was added on Kernel 3.3. The preferred
+ * way to handle such compat stuff would be to include
+ * a recent videodev2.h at ZBar's source and check the
+ * V4L2 API returned by VIDIOC_QUERYCAP.
+ * However, doing that require some care, as other
+ * compat code should be checked to see if they would work.
+ * Also, it is painful to keep updating the Kernel headers.
+ * Thankfully, V4L2_CID_ALPHA_COMPONENT was also added on
+ * Kernel 3.3, so just checking if this is defined should
+ * be enough to do the right thing.
+ */
+ if (!(vid_cap.device_caps & V4L2_CAP_VIDEO_CAPTURE))
+ devices[n_devices].is_valid = 0;
+ else
+ devices[n_devices].is_valid = 1;
+#else
+ if (!(vid_cap.device_caps & V4L2_CAP_VIDEO_CAPTURE))
+ devices[n_devices].is_valid = 0;
+ else
+ devices[n_devices].is_valid = 1;
+#endif
+ }
+ }
+
+ close(fd);
+ } else {
+ devices[n_devices].is_valid = devices[first_device].is_valid;
+ }
+
+ devices[n_devices].fname = strdup(file);
+ devices[n_devices].minor = dev_minor;
+
+ n_devices++;
+
+ return (0);
+}
+
+/* scan /dev for v4l video devices and call add_device for each.
+ * also looks for a specified "default" device (if not NULL)
+ * if not found, the default will be appended to the list.
+ * returns the index+1 of the default_device, or 0 if the default
+ * was not specified. NB *not* reentrant
+ */
+int scan_video(cb_t add_dev, void *userdata, const char *default_dev)
+{
+ unsigned int i, idx = 0;
+ int default_idx = -1, last_minor = -1;
+
+ if (ftw("/dev", handle_video_devs, 4)) {
+ perror("search for video devices failed");
+ return -1;
+ }
+ qsort(devices, n_devices, sizeof(struct devnodes), sort_devices);
+
+ for (i = 0; i < n_devices; i++) {
+ if (!devices[i].is_valid)
+ continue;
+
+ if (devices[i].minor == last_minor)
+ continue;
+
+ add_dev(userdata, devices[i].fname);
+ last_minor = devices[i].minor;
+ idx++;
+
+ if (default_dev && !strcmp(default_dev, devices[i].fname))
+ default_idx = idx;
+ else if (!default_dev && default_idx < 0)
+ default_idx = idx;
+ }
+
+ for (i = 0; i < n_devices; i++)
+ free(devices[i].fname);
+ free(devices);
+
+ n_devices = 0;
+ devices = NULL;
+
+ return (default_idx);
+}
diff --git a/zbarcam/zbarcam-gtk.c b/zbarcam/zbarcam-gtk.c
new file mode 100644
index 0000000..1c7930a
--- /dev/null
+++ b/zbarcam/zbarcam-gtk.c
@@ -0,0 +1,231 @@
+/*------------------------------------------------------------------------
+ * Copyright 2009 (c) Jeff Brown <spadix@users.sourceforge.net>
+ *
+ * This file is part of the ZBar Bar Code Reader.
+ *
+ * The ZBar Bar Code Reader is free software; you can redistribute it
+ * and/or modify it under the terms of the GNU Lesser Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * The ZBar Bar Code Reader is distributed in the hope that it will be
+ * useful, but WITHOUT ANY WARRANTY; without even the implied warranty
+ * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser Public License
+ * along with the ZBar Bar Code Reader; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301 USA
+ *
+ * http://sourceforge.net/projects/zbar
+ *------------------------------------------------------------------------*/
+
+#include <gtk/gtk.h>
+#include <zbar/zbargtk.h>
+
+static GtkWidget *window = NULL;
+static GtkWidget *status_image = NULL;
+static GtkTextView *results = NULL;
+static gchar *open_file = NULL;
+
+int scan_video(void *add_device, void *userdata, const char *default_device);
+
+/* decode signal callback
+ * puts the decoded result in the textbox
+ */
+static void decoded(GtkWidget *widget, zbar_symbol_type_t symbol,
+ const char *result, gpointer data)
+{
+ GtkTextBuffer *resultbuf = gtk_text_view_get_buffer(results);
+ GtkTextIter end;
+ gtk_text_buffer_get_end_iter(resultbuf, &end);
+ gtk_text_buffer_insert(resultbuf, &end, zbar_get_symbol_name(symbol), -1);
+ gtk_text_buffer_insert(resultbuf, &end, ":", -1);
+ gtk_text_buffer_insert(resultbuf, &end, result, -1);
+ gtk_text_buffer_insert(resultbuf, &end, "\n", -1);
+ gtk_text_view_scroll_to_iter(results, &end, 0, FALSE, 0, 0);
+}
+
+/* update button state when video state changes
+ */
+static void video_enabled(GObject *object, GParamSpec *param, gpointer data)
+{
+ ZBarGtk *zbar = ZBAR_GTK(object);
+ gboolean enabled = zbar_gtk_get_video_enabled(zbar);
+ gboolean opened = zbar_gtk_get_video_opened(zbar);
+
+ GtkToggleButton *button = GTK_TOGGLE_BUTTON(data);
+ gboolean active = gtk_toggle_button_get_active(button);
+ if (active != (opened && enabled))
+ gtk_toggle_button_set_active(button, enabled);
+}
+
+static void video_opened(GObject *object, GParamSpec *param, gpointer data)
+{
+ ZBarGtk *zbar = ZBAR_GTK(object);
+ gboolean opened = zbar_gtk_get_video_opened(zbar);
+ gboolean enabled = zbar_gtk_get_video_enabled(zbar);
+
+ gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(data), opened && enabled);
+ gtk_widget_set_sensitive(GTK_WIDGET(data), opened);
+}
+
+/* (re)open the video when a new device is selected
+ */
+static void video_changed(GtkWidget *widget, gpointer data)
+{
+ const char *video_device =
+ gtk_combo_box_text_get_active_text(GTK_COMBO_BOX_TEXT(widget));
+ zbar_gtk_set_video_device(
+ ZBAR_GTK(data),
+ ((video_device && video_device[0] != '<') ? video_device : NULL));
+}
+
+static void status_button_toggled(GtkToggleButton *button, gpointer data)
+{
+ ZBarGtk *zbar = ZBAR_GTK(data);
+ gboolean opened = zbar_gtk_get_video_opened(zbar);
+ gboolean enabled = zbar_gtk_get_video_enabled(zbar);
+ gboolean active = gtk_toggle_button_get_active(button);
+ if (opened && (active != enabled))
+ zbar_gtk_set_video_enabled(ZBAR_GTK(data), active);
+ gtk_image_set_from_icon_name(GTK_IMAGE(status_image),
+ (opened && active) ? "gtk-yes" : "gtk-no",
+ GTK_ICON_SIZE_BUTTON);
+ gtk_button_set_label(GTK_BUTTON(button), (!opened) ? "closed" :
+ (active) ? "enabled" :
+ "disabled");
+}
+
+static void open_button_clicked(GtkButton *button, gpointer data)
+{
+ GtkWidget *dialog =
+ gtk_file_chooser_dialog_new("Open Image File", GTK_WINDOW(window),
+ GTK_FILE_CHOOSER_ACTION_OPEN, "gtk-cancel",
+ GTK_RESPONSE_CANCEL, "gtk-open",
+ GTK_RESPONSE_ACCEPT, NULL);
+ GtkFileChooser *chooser = GTK_FILE_CHOOSER(dialog);
+ if (open_file)
+ gtk_file_chooser_set_filename(chooser, open_file);
+
+ if (gtk_dialog_run(GTK_DIALOG(dialog)) == GTK_RESPONSE_ACCEPT) {
+ gchar *file = gtk_file_chooser_get_filename(chooser);
+ GdkPixbuf *pixbuf = gdk_pixbuf_new_from_file(file, NULL);
+ if (pixbuf)
+ zbar_gtk_scan_image(ZBAR_GTK(data), pixbuf);
+ else
+ fprintf(stderr, "ERROR: unable to open image file: %s\n", file);
+
+ if (open_file && file)
+ g_free(open_file);
+ open_file = file;
+ }
+ gtk_widget_destroy(dialog);
+}
+
+/* build a simple gui w/:
+ * - a combo box to select the desired video device
+ * - the zbar widget to display video
+ * - a non-editable text box to display any results
+ */
+int main(int argc, char *argv[])
+{
+ const char *video_arg = NULL;
+
+ gdk_set_allowed_backends("x11,*");
+ gtk_init(&argc, &argv);
+
+ if (argc > 1)
+ video_arg = argv[1];
+
+ window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
+
+ gtk_window_set_title(GTK_WINDOW(window), "test_gtk");
+ gtk_container_set_border_width(GTK_CONTAINER(window), 8);
+
+ g_signal_connect(G_OBJECT(window), "destroy", G_CALLBACK(gtk_main_quit),
+ NULL);
+
+ GtkWidget *zbar = zbar_gtk_new();
+
+ g_signal_connect(G_OBJECT(zbar), "decoded", G_CALLBACK(decoded), NULL);
+
+ /* video device list combo box */
+ GtkWidget *video_list = gtk_combo_box_text_new();
+
+ g_signal_connect(G_OBJECT(video_list), "changed", G_CALLBACK(video_changed),
+ zbar);
+
+ /* enable/disable status button */
+ GtkWidget *status_button = gtk_toggle_button_new();
+ status_image = gtk_image_new_from_icon_name("gtk-no", GTK_ICON_SIZE_BUTTON);
+ gtk_button_set_image(GTK_BUTTON(status_button), status_image);
+ gtk_button_set_label(GTK_BUTTON(status_button), "closed");
+ gtk_widget_set_sensitive(status_button, FALSE);
+
+ /* bind status button state and video state */
+ g_signal_connect(G_OBJECT(status_button), "toggled",
+ G_CALLBACK(status_button_toggled), zbar);
+ g_signal_connect(G_OBJECT(zbar), "notify::video-enabled",
+ G_CALLBACK(video_enabled), status_button);
+ g_signal_connect(G_OBJECT(zbar), "notify::video-opened",
+ G_CALLBACK(video_opened), status_button);
+
+ /* open image file button */
+#if GTK_MAJOR_VERSION >= 3
+ GtkWidget *open_button =
+ gtk_button_new_from_icon_name("gtk-open", GTK_ICON_SIZE_BUTTON);
+#else
+ GtkWidget *open_button = gtk_button_new_from_stock(GTK_STOCK_OPEN);
+#endif
+
+ g_signal_connect(G_OBJECT(open_button), "clicked",
+ G_CALLBACK(open_button_clicked), zbar);
+
+ gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(video_list), "<none>");
+ int active =
+ scan_video(gtk_combo_box_text_append_text, video_list, video_arg);
+ if (active >= 0)
+ gtk_combo_box_set_active(GTK_COMBO_BOX(video_list), active);
+
+ /* hbox for combo box and buttons */
+#if GTK_MAJOR_VERSION >= 3
+ GtkWidget *hbox = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 8);
+#else
+ GtkWidget *hbox = gtk_hbox_new(FALSE, 8);
+#endif
+
+ gtk_box_pack_start(GTK_BOX(hbox), video_list, TRUE, TRUE, 0);
+ gtk_box_pack_start(GTK_BOX(hbox), status_button, FALSE, FALSE, 0);
+ gtk_box_pack_start(GTK_BOX(hbox), open_button, FALSE, FALSE, 0);
+
+ /* text box for holding results */
+ results = GTK_TEXT_VIEW(gtk_text_view_new());
+ gtk_widget_set_size_request(GTK_WIDGET(results), 320, 64);
+ gtk_text_view_set_editable(results, FALSE);
+ gtk_text_view_set_cursor_visible(results, FALSE);
+ gtk_text_view_set_left_margin(results, 4);
+
+ /* vbox for hbox, zbar test widget and result text box */
+#if GTK_MAJOR_VERSION >= 3
+ GtkWidget *vbox = gtk_box_new(GTK_ORIENTATION_VERTICAL, 8);
+#else
+ GtkWidget *vbox = gtk_vbox_new(FALSE, 8);
+#endif
+ gtk_container_add(GTK_CONTAINER(window), vbox);
+
+ gtk_box_pack_start(GTK_BOX(vbox), hbox, FALSE, FALSE, 0);
+ gtk_box_pack_start(GTK_BOX(vbox), zbar, TRUE, TRUE, 0);
+ gtk_box_pack_start(GTK_BOX(vbox), GTK_WIDGET(results), FALSE, FALSE, 0);
+
+ GdkGeometry hints;
+ hints.min_width = 320;
+ hints.min_height = 240;
+ gtk_window_set_geometry_hints(GTK_WINDOW(window), zbar, &hints,
+ GDK_HINT_MIN_SIZE);
+
+ gtk_widget_show_all(window);
+ gtk_main();
+ return (0);
+}
diff --git a/zbarcam/zbarcam-qt.cpp b/zbarcam/zbarcam-qt.cpp
new file mode 100644
index 0000000..b98a32a
--- /dev/null
+++ b/zbarcam/zbarcam-qt.cpp
@@ -0,0 +1,1050 @@
+//------------------------------------------------------------------------
+// Copyright 2008-2009 (c) Jeff Brown <spadix@users.sourceforge.net>
+//
+// This file is part of the ZBar Bar Code Reader.
+//
+// The ZBar Bar Code Reader is free software; you can redistribute it
+// and/or modify it under the terms of the GNU Lesser Public License as
+// published by the Free Software Foundation; either version 2.1 of
+// the License, or (at your option) any later version.
+//
+// The ZBar Bar Code Reader is distributed in the hope that it will be
+// useful, but WITHOUT ANY WARRANTY; without even the implied warranty
+// of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU Lesser Public License for more details.
+//
+// You should have received a copy of the GNU Lesser Public License
+// along with the ZBar Bar Code Reader; if not, write to the Free
+// Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+// Boston, MA 02110-1301 USA
+//
+// http://sourceforge.net/projects/zbar
+//------------------------------------------------------------------------
+
+#include <QApplication>
+#include <QCheckBox>
+#include <QComboBox>
+#include <QCommandLineParser>
+#include <QFileDialog>
+#include <QImage>
+#include <QLayout>
+#include <QPushButton>
+#include <QTextEdit>
+#include <QWidget>
+#include <QtGlobal>
+#include <config.h>
+#include <zbar.h>
+#include <zbar/QZBar.h>
+
+#define TEST_IMAGE_FORMATS \
+ "Image Files (*.png *.jpg *.jpeg *.bmp *.gif *.ppm *.pgm *.pbm *.tiff " \
+ "*.xpm *.xbm)"
+
+#define SYM_GROUP "Symbology"
+#define CAM_GROUP "Camera"
+#define DBUS_NAME "D-Bus"
+#define OPTION_BAR "option_bar.enable"
+#define CONTROL_BAR "control_bar.enable"
+
+extern "C" {
+int scan_video(void *add_device, void *userdata, const char *default_device);
+}
+
+struct configs_s {
+ QString name;
+ zbar::zbar_symbol_type_t sym;
+};
+
+static const struct configs_s configs[] = {
+ { "Composite codes", zbar::ZBAR_COMPOSITE },
+ { "Image Scanner", zbar::ZBAR_PARTIAL },
+#if ENABLE_CODABAR == 1
+ { "Codabar", zbar::ZBAR_CODABAR },
+#endif
+#if ENABLE_CODE128 == 1
+ { "Code-128", zbar::ZBAR_CODE128 },
+#endif
+#if ENABLE_I25 == 1
+ { "Code 2 of 5 interlaced", zbar::ZBAR_I25 },
+#endif
+#if ENABLE_CODE39 == 1
+ { "Code-39", zbar::ZBAR_CODE39 },
+#endif
+#if ENABLE_CODE93 == 1
+ { "Code-93", zbar::ZBAR_CODE93 },
+#endif
+#if ENABLE_DATABAR == 1
+ { "DataBar", zbar::ZBAR_DATABAR },
+ { "DataBar expanded", zbar::ZBAR_DATABAR_EXP },
+#endif
+#if ENABLE_EAN == 1
+ { "EAN-2", zbar::ZBAR_EAN2 },
+ { "EAN-5", zbar::ZBAR_EAN5 },
+ { "EAN-8", zbar::ZBAR_EAN8 },
+ { "EAN-13", zbar::ZBAR_EAN13 },
+ { "ISBN-10", zbar::ZBAR_ISBN10 },
+ { "ISBN-13", zbar::ZBAR_ISBN13 },
+ { "UPC-A", zbar::ZBAR_UPCA },
+ { "UPC-E", zbar::ZBAR_UPCE },
+#endif
+#if ENABLE_PDF417 == 1
+ { "PDF417", zbar::ZBAR_PDF417 },
+#endif
+#if ENABLE_QRCODE == 1
+ { "QR code", zbar::ZBAR_QRCODE },
+#endif
+#if ENABLE_SQCODE == 1
+ { "SQ code", zbar::ZBAR_SQCODE },
+#endif
+};
+
+#define CONFIGS_SIZE (sizeof(configs) / sizeof(*configs))
+
+struct settings_s {
+ QString name;
+ zbar::zbar_config_t ctrl;
+ bool is_bool;
+};
+
+static const struct settings_s settings[] = {
+ { "x-density", zbar::ZBAR_CFG_Y_DENSITY, false },
+ { "y-density", zbar::ZBAR_CFG_Y_DENSITY, false },
+ { "min-length", zbar::ZBAR_CFG_MIN_LEN, false },
+ { "max-length", zbar::ZBAR_CFG_MAX_LEN, false },
+ { "uncertainty", zbar::ZBAR_CFG_UNCERTAINTY, false },
+ { "ascii", zbar::ZBAR_CFG_ASCII, true },
+ { "binary", zbar::ZBAR_CFG_BINARY, true },
+ { "add-check", zbar::ZBAR_CFG_ADD_CHECK, true },
+ { "emit-check", zbar::ZBAR_CFG_EMIT_CHECK, true },
+ { "position", zbar::ZBAR_CFG_POSITION, true },
+ { "test-inverted", zbar::ZBAR_CFG_TEST_INVERTED, true },
+};
+#define SETTINGS_SIZE (sizeof(settings) / sizeof(*settings))
+
+// Represents an integer control
+
+class IntegerControl : public QSpinBox
+{
+ Q_OBJECT
+
+private:
+ char *name;
+ zbar::QZBar *zbar;
+
+private slots:
+ void updateControl(int value);
+
+public:
+ IntegerControl(QGroupBox *parent, zbar::QZBar *_zbar, char *_name, int min,
+ int max, int def, int step)
+ : QSpinBox(parent)
+ {
+ int val;
+
+ zbar = _zbar;
+ name = _name;
+
+ setRange(min, max);
+ setSingleStep(step);
+ if (!zbar->get_control(name, &val))
+ setValue(val);
+ else
+ setValue(def);
+
+ connect(this, SIGNAL(valueChanged(int)), this,
+ SLOT(updateControl(int)));
+ }
+};
+
+void IntegerControl::updateControl(int value)
+{
+ zbar->set_control(name, value);
+}
+
+// Represents a menu control
+class MenuControl : public QComboBox
+{
+ Q_OBJECT
+
+private:
+ char *name;
+ zbar::QZBar *zbar;
+ QVector<QPair<int, QString> > vector;
+
+private slots:
+ void updateControl(int value);
+
+public:
+ MenuControl(QGroupBox *parent, zbar::QZBar *_zbar, char *_name,
+ QVector<QPair<int, QString> > _vector)
+ : QComboBox(parent)
+ {
+ int val;
+
+ zbar = _zbar;
+ name = _name;
+ vector = _vector;
+
+ if (zbar->get_control(name, &val))
+ val = 0;
+ for (int i = 0; i < vector.size(); ++i) {
+ QPair<int, QString> pair = vector.at(i);
+ addItem(pair.second, pair.first);
+
+ if (val == pair.first)
+ setCurrentIndex(i);
+ }
+ connect(this, SIGNAL(currentIndexChanged(int)), this,
+ SLOT(updateControl(int)));
+ }
+};
+
+void MenuControl::updateControl(int index)
+{
+ zbar->set_control(name, vector.at(index).first);
+}
+
+class IntegerSetting : public QSpinBox
+{
+ Q_OBJECT
+
+public:
+ QString name;
+
+ IntegerSetting(QString _name, int val = 0) : name(_name)
+ {
+ setValue(val);
+ }
+};
+
+class SettingsDialog : public QDialog
+{
+ Q_OBJECT
+
+private:
+ QVector<int> val;
+ zbar::QZBar *zbar;
+ zbar::zbar_symbol_type_t sym;
+
+private slots:
+
+ void accept()
+ {
+ for (unsigned i = 0; i < SETTINGS_SIZE; i++)
+ zbar->set_config(sym, settings[i].ctrl, val[i]);
+ QDialog::accept();
+ };
+ void reject()
+ {
+ QDialog::reject();
+ };
+ void clicked()
+ {
+ QCheckBox *button = qobject_cast<QCheckBox *>(sender());
+ if (!button)
+ return;
+
+ QString name = button->text();
+
+ for (unsigned i = 0; i < SETTINGS_SIZE; i++) {
+ if (settings[i].name == name) {
+ val[i] = button->isChecked();
+ return;
+ }
+ }
+ // ERROR!
+ };
+ void update(int value)
+ {
+ IntegerSetting *setting = qobject_cast<IntegerSetting *>(sender());
+ if (!setting)
+ return;
+
+ for (unsigned i = 0; i < SETTINGS_SIZE; i++) {
+ if (settings[i].name == setting->name) {
+ val[i] = value;
+ return;
+ }
+ }
+ // ERROR!
+ };
+
+public:
+ SettingsDialog(zbar::QZBar *_zbar, QString &name,
+ zbar::zbar_symbol_type_t _sym)
+ : zbar(_zbar), sym(_sym)
+ {
+ val = QVector<int>(SETTINGS_SIZE);
+
+ QGridLayout *layout = new QGridLayout(this);
+
+ this->setWindowTitle(name);
+
+ for (unsigned i = 0; i < SETTINGS_SIZE; i++) {
+ int value = 0;
+
+ if (zbar->get_config(sym, settings[i].ctrl, value))
+ continue;
+ val[i] = value;
+
+ if (settings[i].is_bool) {
+ QCheckBox *button = new QCheckBox(settings[i].name, this);
+
+ button->setChecked(value);
+
+ layout->addWidget(button, i, 0, 1, 2,
+ Qt::AlignTop | Qt::AlignLeft);
+ connect(button, SIGNAL(clicked()), this, SLOT(clicked()));
+ } else {
+ QLabel *label = new QLabel(settings[i].name);
+
+ layout->addWidget(label, i, 0, 1, 1,
+ Qt::AlignTop | Qt::AlignLeft);
+ IntegerSetting *spin =
+ new IntegerSetting(settings[i].name, value);
+ layout->addWidget(spin, i, 1, 1, 1,
+ Qt::AlignTop | Qt::AlignLeft);
+ connect(spin, SIGNAL(valueChanged(int)), this,
+ SLOT(update(int)));
+ }
+ }
+ QDialogButtonBox *buttonBox = new QDialogButtonBox(
+ QDialogButtonBox::Ok | QDialogButtonBox::Cancel);
+ connect(buttonBox, SIGNAL(accepted()), this, SLOT(accept()));
+ connect(buttonBox, SIGNAL(rejected()), this, SLOT(reject()));
+ layout->addWidget(buttonBox);
+ }
+};
+
+class SettingsButton : public QPushButton
+{
+ Q_OBJECT
+
+private:
+ QString name;
+ zbar::QZBar *zbar;
+ zbar::zbar_symbol_type_t sym;
+
+public:
+ SettingsButton(zbar::QZBar *_zbar, const QIcon &_icon, QString _name,
+ zbar::zbar_symbol_type_t _sym)
+ : QPushButton(_icon, ""), name(_name), zbar(_zbar), sym(_sym)
+ {
+ int size = font().pointSize();
+
+ if (size < 0)
+ size = font().pixelSize();
+
+ if (size > 0)
+ setIconSize(QSize(size, size));
+ };
+
+public Q_SLOTS:
+ void button_clicked()
+ {
+ SettingsButton *button = qobject_cast<SettingsButton *>(sender());
+ if (!button)
+ return;
+
+ QString name = button->name;
+
+ SettingsDialog *dialog = new SettingsDialog(zbar, name, sym);
+ dialog->setModal(true);
+ dialog->show();
+ }
+};
+
+struct CamRes {
+ unsigned width;
+ unsigned height;
+ float max_fps;
+};
+
+class ZbarcamQZBar : public QWidget
+{
+ Q_OBJECT
+
+protected:
+ static void add_device(QComboBox *list, const char *device)
+ {
+ list->addItem(QString(device));
+ }
+
+public Q_SLOTS:
+ void turn_show_options()
+ {
+ QPushButton *button = qobject_cast<QPushButton *>(sender());
+ if (!button)
+ return;
+
+ show_options = !show_options;
+ if (show_options) {
+ button->setText("Hide Options");
+ optionsGroup->show();
+ } else {
+ button->setText("Show Options");
+ optionsGroup->hide();
+ }
+ }
+
+ void turn_show_controls()
+ {
+ QPushButton *button = qobject_cast<QPushButton *>(sender());
+ if (!button)
+ return;
+
+ show_controls = !show_controls;
+ if (show_controls) {
+ button->setText("Hide Controls");
+ controlGroup->show();
+ } else {
+ button->setText("Show Controls");
+ controlGroup->hide();
+ }
+ }
+
+public:
+ ~ZbarcamQZBar()
+ {
+ saveSettings();
+ }
+ ZbarcamQZBar(const QStringList *names, int verbose = 0) : resolutions(NULL)
+ {
+ // drop-down list of video devices
+ QComboBox *videoList = new QComboBox;
+
+ // toggle button to disable/enable video
+ statusButton = new QPushButton;
+
+ QStyle *style = QApplication::style();
+ QIcon statusIcon = style->standardIcon(QStyle::SP_DialogNoButton);
+ QIcon yesIcon = style->standardIcon(QStyle::SP_DialogYesButton);
+ statusIcon.addPixmap(yesIcon.pixmap(QSize(128, 128), QIcon::Normal,
+ QIcon::On),
+ QIcon::Normal, QIcon::On);
+
+ statusButton->setIcon(statusIcon);
+ statusButton->setText("&Enable");
+ statusButton->setCheckable(true);
+ statusButton->setEnabled(false);
+ statusButton->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed);
+
+ // command button to open image files for scanning
+ QPushButton *openButton = new QPushButton("&Open");
+ QIcon openIcon = style->standardIcon(QStyle::SP_DialogOpenButton);
+ openButton->setIcon(openIcon);
+ openButton->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed);
+
+ // collect video list and buttons horizontally
+ ZBarMenu = new QHBoxLayout;
+ ZBarMenu->setAlignment(Qt::AlignLeft);
+ ZBarMenu->addWidget(videoList, 5);
+ ZBarMenu->addWidget(statusButton, 1);
+ ZBarMenu->addWidget(openButton, 1);
+
+ // video barcode scanner
+ zbar = new zbar::QZBar(NULL, verbose);
+ zbar->setAcceptDrops(true);
+
+ // text box for results
+ QTextEdit *results = new QTextEdit;
+ results->setReadOnly(true);
+
+ QGridLayout *grid = new QGridLayout;
+ grid->addLayout(ZBarMenu, 0, 0, 1, -1);
+ grid->addWidget(zbar, 1, 0, 1, 1);
+ grid->addWidget(results, 2, 0, 1, 1);
+
+ // Group box where controls will be added
+ optionsGroup = new QGroupBox(tr("Options"), this);
+ QGridLayout *optionsBoxLayout = new QGridLayout(optionsGroup);
+ optionsGroup->setAlignment(Qt::AlignHCenter);
+ optionsBoxLayout->setContentsMargins(0, 0, 16, 0);
+ grid->addWidget(optionsGroup, 1, 1, -1, 1, Qt::AlignTop);
+
+ controlGroup = new QGroupBox(this);
+ controlBoxLayout = new QGridLayout(controlGroup);
+ controlBoxLayout->setContentsMargins(0, 0, 0, 0);
+ grid->addWidget(controlGroup, 1, 2, -1, 1, Qt::AlignTop);
+
+ loadSettings();
+ zbar->request_size(curWidth, curHeight, false);
+
+ int pos = 0;
+
+#ifdef HAVE_DBUS
+ QCheckBox *button = new QCheckBox(DBUS_NAME, this);
+ button->setChecked(dbus_enabled);
+ optionsBoxLayout->addWidget(button, ++pos, 0, 1, 1,
+ Qt::AlignTop | Qt::AlignLeft);
+ connect(button, SIGNAL(clicked()), this, SLOT(code_clicked()));
+ zbar->request_dbus(0);
+#endif
+
+ for (unsigned i = 0; i < CONFIGS_SIZE; i++) {
+ int val = 0;
+
+ if (configs[i].sym == zbar::ZBAR_PARTIAL) {
+ QLabel *label = new QLabel(configs[i].name, this);
+ optionsBoxLayout->addWidget(label, ++pos, 0, 1, 1,
+ Qt::AlignTop | Qt::AlignLeft);
+ } else {
+ QCheckBox *button = new QCheckBox(configs[i].name, this);
+
+ zbar->get_config(configs[i].sym, zbar::ZBAR_CFG_ENABLE, val);
+
+ button->setChecked(val);
+ optionsBoxLayout->addWidget(button, ++pos, 0, 1, 1,
+ Qt::AlignTop | Qt::AlignLeft);
+ connect(button, SIGNAL(clicked()), this, SLOT(code_clicked()));
+ }
+
+ /* Composite doesn't have configuration */
+ if (configs[i].sym == zbar::ZBAR_COMPOSITE)
+ continue;
+
+ QIcon icon = QIcon::fromTheme(QLatin1String("configure-toolbars"));
+ SettingsButton *settings =
+ new SettingsButton(zbar, icon, configs[i].name, configs[i].sym);
+ optionsBoxLayout->addWidget(settings, pos, 1, 1, 1,
+ Qt::AlignTop | Qt::AlignLeft);
+
+ connect(settings, &SettingsButton::clicked, settings,
+ &SettingsButton::button_clicked);
+ }
+
+ // Allow showing/hiding options/controls menus
+ QPushButton *showOptionsButton, *showControlsButton;
+
+ if (show_options) {
+ showOptionsButton = new QPushButton("Hide Options");
+ optionsGroup->show();
+ } else {
+ showOptionsButton = new QPushButton("Show Options");
+ optionsGroup->hide();
+ }
+ showOptionsButton->setSizePolicy(QSizePolicy::Fixed,
+ QSizePolicy::Fixed);
+ ZBarMenu->addWidget(showOptionsButton);
+ connect(showOptionsButton, SIGNAL(clicked()), this,
+ SLOT(turn_show_options()));
+
+ if (show_controls) {
+ showControlsButton = new QPushButton("Hide Controls");
+ controlGroup->show();
+ } else {
+ showControlsButton = new QPushButton("Show Controls");
+ controlGroup->hide();
+ }
+ showControlsButton->setSizePolicy(QSizePolicy::Fixed,
+ QSizePolicy::Fixed);
+ ZBarMenu->addWidget(showControlsButton);
+ connect(showControlsButton, SIGNAL(clicked()), this,
+ SLOT(turn_show_controls()));
+
+ if (!geometry.isEmpty())
+ restoreGeometry(geometry);
+
+ setLayout(grid);
+
+ videoList->addItem("");
+
+ int active = 0;
+ for (int i = 0; i < names->size(); i++)
+ active += scan_video((void *)add_device, videoList,
+ names->at(i).toUtf8());
+
+ if (names->isEmpty())
+ active += scan_video((void *)add_device, videoList, NULL);
+
+ // directly connect combo box change signal to scanner video open
+ connect(videoList, SIGNAL(currentIndexChanged(const QString &)), zbar,
+ SLOT(setVideoDevice(const QString &)));
+
+ // directly connect status button state to video enabled state
+ connect(statusButton, SIGNAL(toggled(bool)), zbar,
+ SLOT(setVideoEnabled(bool)));
+
+ // also update status button state when video is opened/closed
+ connect(zbar, SIGNAL(videoOpened(bool)), this, SLOT(setEnabled(bool)));
+
+ // prompt for image file to scan when openButton is clicked
+ connect(openButton, SIGNAL(clicked()), SLOT(openImage()));
+
+ // directly connect video scanner decode result to display in text box
+ connect(zbar, SIGNAL(decodedText(const QString &)), results,
+ SLOT(append(const QString &)));
+
+ if (active >= 0)
+ videoList->setCurrentIndex(active);
+ }
+
+public Q_SLOTS:
+ void openImage()
+ {
+ file = QFileDialog::getOpenFileName(this, "Open Image", file,
+ TEST_IMAGE_FORMATS);
+ if (!file.isEmpty())
+ zbar->scanImage(QImage(file));
+ }
+
+ void control_clicked()
+ {
+ QCheckBox *button = qobject_cast<QCheckBox *>(sender());
+ if (!button)
+ return;
+
+ QString name = button->text();
+ bool val = button->isChecked();
+
+ zbar->set_control(name.toUtf8().data(), val);
+ }
+
+ void code_clicked()
+ {
+ QCheckBox *button = qobject_cast<QCheckBox *>(sender());
+ if (!button)
+ return;
+
+ QString name = button->text();
+ bool val = button->isChecked();
+
+ if (name == DBUS_NAME) {
+ zbar->request_dbus(val);
+ dbus_enabled = val;
+ return;
+ }
+
+ for (unsigned i = 0; i < CONFIGS_SIZE; i++) {
+ if (configs[i].name == name) {
+ zbar->set_config(configs[i].sym, zbar::ZBAR_CFG_ENABLE, val);
+ return;
+ }
+ }
+ }
+
+ void clearLayout(QLayout *layout)
+ {
+ QLayoutItem *item;
+ while ((item = layout->takeAt(0))) {
+ if (item->layout()) {
+ clearLayout(item->layout());
+ delete item->layout();
+ }
+ if (item->widget()) {
+ delete item->widget();
+ }
+ delete item;
+ }
+ }
+
+ void setVideoResolution(int index)
+ {
+ struct CamRes *cur_res;
+
+ if (index < 0 || res.isEmpty())
+ return;
+
+ cur_res = &res[index];
+
+ unsigned width = zbar->videoWidth();
+ unsigned height = zbar->videoHeight();
+
+ if (width == cur_res->width && height == cur_res->height)
+ return;
+
+ zbar->request_size(cur_res->width, cur_res->height);
+
+ curWidth = cur_res->width;
+ curHeight = cur_res->height;
+ }
+
+ void setEnabled(bool videoEnabled)
+ {
+ zbar->setVideoEnabled(videoEnabled);
+
+ // Update the status button
+ statusButton->setEnabled(videoEnabled);
+ statusButton->setChecked(videoEnabled);
+
+ // Delete items before creating a new set of controls
+ clearLayout(controlBoxLayout);
+
+ if (!videoEnabled)
+ return;
+
+ // get_controls
+ loadSettings(false);
+
+ // FIXME: clear a previous resolutions box
+
+ bool isNewResolutions = false;
+
+ if (!resolutions) {
+ resolutions = new QComboBox;
+ resolutions->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed);
+ isNewResolutions = true;
+ }
+
+ resolutions->blockSignals(true);
+ res.clear();
+ resolutions->clear();
+
+ for (int i = 0;; i++) {
+ QString new_res, fps;
+ struct CamRes cur_res;
+
+ if (!zbar->get_resolution(i, cur_res.width, cur_res.height,
+ cur_res.max_fps))
+ break;
+
+ fps.setNum(cur_res.max_fps, 'f', 2);
+ new_res = QString("%1x%2 - %3 fps (max)")
+ .arg(cur_res.width)
+ .arg(cur_res.height)
+ .arg(fps);
+
+ resolutions->addItem(new_res);
+ res.append(cur_res);
+
+ if (curWidth == cur_res.width && curHeight == cur_res.height)
+ resolutions->setCurrentIndex(i);
+ }
+
+ if (isNewResolutions) {
+ ZBarMenu->addWidget(resolutions);
+ connect(resolutions, SIGNAL(currentIndexChanged(int)), this,
+ SLOT(setVideoResolution(int)));
+ }
+ resolutions->blockSignals(false);
+
+ // Restore saved resolution
+ unsigned width = zbar->videoWidth();
+ unsigned height = zbar->videoHeight();
+
+ if (width != curWidth || height != curHeight) {
+ for (int i = 0; i < res.size(); i++) {
+ if (res[i].width == curWidth && res[i].height == curHeight) {
+ resolutions->setCurrentIndex(i);
+ break;
+ }
+ }
+ }
+
+ int pos = 0;
+ QString oldGroup = "";
+ for (int i = 0;; i++) {
+ char *name, *group;
+ enum zbar::QZBar::ControlType type;
+ int min, max, def, step;
+
+ int ret = zbar->get_controls(i, &name, &group, &type, &min, &max,
+ &def, &step);
+ if (!ret)
+ break;
+
+ QString newGroup =
+ "<strong>" + QString::fromUtf8(group) + " Controls</strong>";
+
+ if (newGroup != oldGroup) {
+ if (oldGroup != "")
+ controlBoxLayout->addItem(new QSpacerItem(0, 12), pos++, 2,
+ 1, 2, Qt::AlignLeft);
+ QLabel *label = new QLabel(newGroup);
+ controlBoxLayout->addWidget(label, pos++, 0, 1, 2,
+ Qt::AlignTop | Qt::AlignHCenter);
+ pos++;
+ oldGroup = newGroup;
+ }
+
+ switch (type) {
+ case zbar::QZBar::Button:
+ case zbar::QZBar::Boolean: {
+ bool val;
+
+ QCheckBox *button = new QCheckBox(name, controlGroup);
+ controlBoxLayout->addWidget(button, pos++, 0, 1, 2,
+ Qt::AlignLeft);
+
+ if (!zbar->get_control(name, &val))
+ button->setChecked(val);
+ else
+ button->setChecked(def);
+ connect(button, SIGNAL(clicked()), this,
+ SLOT(control_clicked()));
+ break;
+ }
+ case zbar::QZBar::Integer: {
+ IntegerControl *ctrl;
+
+ QLabel *label = new QLabel(QString::fromUtf8(name));
+ ctrl = new IntegerControl(controlGroup, zbar, name, min, max,
+ def, step);
+
+ controlBoxLayout->addWidget(label, pos, 0, Qt::AlignLeft);
+ controlBoxLayout->addWidget(ctrl, pos++, 1, Qt::AlignLeft);
+ break;
+ }
+ case zbar::QZBar::Menu: {
+ MenuControl *ctrl;
+
+ QLabel *label = new QLabel(QString::fromUtf8(name));
+
+ QVector<QPair<int, QString> > vector;
+ vector = zbar->get_menu(i);
+ ctrl = new MenuControl(controlGroup, zbar, name, vector);
+
+ controlBoxLayout->addWidget(label, pos, 0, Qt::AlignLeft);
+ controlBoxLayout->addWidget(ctrl, pos++, 1, Qt::AlignLeft);
+ break;
+ }
+ default:
+ // Just ignore other types
+ break;
+ }
+ }
+ }
+
+private:
+ QString file;
+ zbar::QZBar *zbar;
+ QHBoxLayout *ZBarMenu;
+ QPushButton *statusButton;
+ QGroupBox *controlGroup, *optionsGroup;
+ QComboBox *resolutions;
+ QGridLayout *controlBoxLayout;
+ QSignalMapper *signalMapper;
+ bool dbus_enabled, show_options, show_controls;
+ QByteArray geometry;
+ QVector<struct CamRes> res;
+ unsigned curWidth, curHeight;
+
+ void loadSettings(bool getRes = true)
+ {
+ QSettings qSettings(QCoreApplication::organizationName(),
+ QCoreApplication::applicationName());
+ QString key;
+ QVariant qVal;
+
+ geometry = qSettings.value("geometry").toByteArray();
+
+ key = OPTION_BAR;
+ qVal = qSettings.value(key, true);
+ show_options = qVal.toBool();
+
+ key = CONTROL_BAR;
+ qVal = qSettings.value(key, true);
+ show_controls = qVal.toBool();
+
+ if (getRes) {
+ qVal = qSettings.value("width");
+ curWidth = qVal.toUInt();
+ qVal = qSettings.value("height");
+ curHeight = qVal.toUInt();
+ }
+
+#ifdef HAVE_DBUS
+ key = DBUS_NAME ".enable";
+ qVal = qSettings.value(key, false);
+ dbus_enabled = qVal.toBool();
+#endif
+
+ qSettings.beginGroup(SYM_GROUP);
+
+ for (unsigned i = 0; i < CONFIGS_SIZE; i++) {
+ int val = 0;
+ if (zbar->get_config(configs[i].sym, zbar::ZBAR_CFG_ENABLE, val))
+ continue;
+ key = QString(configs[i].name) + QString(".enable");
+ key.replace(" ", "_");
+ qVal = qSettings.value(key, val);
+ zbar->set_config(configs[i].sym, zbar::ZBAR_CFG_ENABLE,
+ qVal.toInt());
+
+ if (configs[i].sym == zbar::ZBAR_COMPOSITE)
+ continue;
+
+ for (unsigned j = 0; j < SETTINGS_SIZE; j++) {
+ int val = 0;
+
+ if (zbar->get_config(configs[i].sym, settings[j].ctrl, val))
+ continue;
+ key = QString(configs[i].name) + QString(".") +
+ QString(settings[j].name);
+ key.replace(" ", "_");
+
+ qVal = qSettings.value(key, val);
+ zbar->set_config(configs[i].sym, settings[j].ctrl,
+ qVal.toInt());
+ }
+ }
+ qSettings.endGroup();
+
+ qSettings.beginGroup(CAM_GROUP);
+ for (unsigned i = 0;; i++) {
+ char *name, *group;
+ enum zbar::QZBar::ControlType type;
+ int min, max, def, step, val;
+
+ int ret = zbar->get_controls(i, &name, &group, &type, &min, &max,
+ &def, &step);
+ if (!ret)
+ break;
+
+ switch (type) {
+ case zbar::QZBar::Button:
+ case zbar::QZBar::Boolean:
+ case zbar::QZBar::Menu:
+ case zbar::QZBar::Integer: {
+ key = QString::fromUtf8(name);
+
+ if (zbar->get_control(name, &val))
+ continue;
+
+ key.replace(QRegularExpression("[^\\w\\d]+"), "_");
+ key.replace(QRegularExpression("_$"), "");
+
+ qVal = qSettings.value(key, val);
+ zbar->set_control(name, qVal.toInt());
+ break;
+ }
+ default:
+ // Just ignore other types
+ break;
+ }
+ }
+ qSettings.endGroup();
+ }
+
+ void saveSettings()
+ {
+ QSettings qSettings(QCoreApplication::organizationName(),
+ QCoreApplication::applicationName());
+ QString key;
+ unsigned int i;
+
+ qSettings.setValue("geometry", saveGeometry());
+
+ key = OPTION_BAR;
+ qSettings.setValue(key, show_options);
+
+ key = CONTROL_BAR;
+ qSettings.setValue(key, show_controls);
+
+ curWidth = zbar->videoWidth();
+ curHeight = zbar->videoHeight();
+ qSettings.setValue("width", curWidth);
+ qSettings.setValue("height", curHeight);
+
+#ifdef HAVE_DBUS
+ // FIXME: track dbus enable-disable and store last state
+ key = DBUS_NAME ".enable";
+ qSettings.setValue(key, dbus_enabled);
+#endif
+
+ qSettings.beginGroup(SYM_GROUP);
+ for (i = 0; i < CONFIGS_SIZE; i++) {
+ int val = 0;
+
+ if (zbar->get_config(configs[i].sym, zbar::ZBAR_CFG_ENABLE, val))
+ continue;
+ key = QString(configs[i].name) + QString(".enable");
+ key.replace(" ", "_");
+ qSettings.setValue(key, val);
+
+ if (configs[i].sym == zbar::ZBAR_COMPOSITE)
+ continue;
+
+ for (unsigned j = 0; j < SETTINGS_SIZE; j++) {
+ int val = 0;
+
+ if (zbar->get_config(configs[i].sym, settings[j].ctrl, val))
+ continue;
+ key = QString(configs[i].name) + QString(".") +
+ QString(settings[j].name);
+ key.replace(" ", "_");
+ qSettings.setValue(key, val);
+ }
+ }
+ qSettings.endGroup();
+
+ for (i = 0;; i++) {
+ char *name, *group;
+ enum zbar::QZBar::ControlType type;
+ int min, max, def, step, val;
+
+ int ret = zbar->get_controls(i, &name, &group, &type, &min, &max,
+ &def, &step);
+ if (!ret)
+ break;
+
+ if (i == 0)
+ qSettings.beginGroup(CAM_GROUP);
+
+ switch (type) {
+ case zbar::QZBar::Button:
+ case zbar::QZBar::Boolean:
+ case zbar::QZBar::Menu:
+ case zbar::QZBar::Integer: {
+ key = QString::fromUtf8(name);
+
+ if (zbar->get_control(name, &val))
+ continue;
+
+ key.replace(QRegularExpression("[^\\w\\d]+"), "_");
+ key.replace(QRegularExpression("_$"), "");
+ qSettings.setValue(key, val);
+ break;
+ }
+ default:
+ // Just ignore other types
+ break;
+ }
+ }
+ if (i > 0)
+ qSettings.endGroup();
+ }
+};
+
+#include "moc_zbarcam_qt.h"
+
+int main(int argc, char *argv[])
+{
+ int verbose = 0;
+ QApplication app(argc, argv);
+ app.setApplicationName("zbarcam_qt");
+ app.setOrganizationName("LinuxTV");
+ app.setOrganizationDomain("linuxtv.org");
+ app.setAttribute(Qt::AA_UseHighDpiPixmaps, true);
+
+ QCommandLineParser parser;
+ parser.setApplicationDescription("ZBar bar code reader Qt application");
+ parser.addHelpOption();
+
+ parser.addPositionalArgument("name", QObject::tr("device or file name"));
+
+ QCommandLineOption debugOption(QStringList() << "d"
+ << "debug",
+ QObject::tr("Enable debug mode."));
+ parser.addOption(debugOption);
+
+ QCommandLineOption verboseOption(QStringList() << "v"
+ << "verbosity",
+ QObject::tr("Verbosity level."),
+ QObject::tr("value"));
+ parser.addOption(verboseOption);
+
+ parser.process(app);
+
+ if (parser.isSet(verboseOption))
+ verbose = parser.value(verboseOption).toInt();
+
+ if (parser.isSet(debugOption))
+ verbose = 127;
+
+ const QStringList args = parser.positionalArguments();
+
+ ZbarcamQZBar window(&args, verbose);
+ window.show();
+ return (app.exec());
+}
diff --git a/zbarcam/zbarcam.c b/zbarcam/zbarcam.c
new file mode 100644
index 0000000..040c030
--- /dev/null
+++ b/zbarcam/zbarcam.c
@@ -0,0 +1,375 @@
+/*------------------------------------------------------------------------
+ * Copyright 2007-2009 (c) Jeff Brown <spadix@users.sourceforge.net>
+ *
+ * This file is part of the ZBar Bar Code Reader.
+ *
+ * The ZBar Bar Code Reader is free software; you can redistribute it
+ * and/or modify it under the terms of the GNU Lesser Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * The ZBar Bar Code Reader is distributed in the hope that it will be
+ * useful, but WITHOUT ANY WARRANTY; without even the implied warranty
+ * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser Public License
+ * along with the ZBar Bar Code Reader; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301 USA
+ *
+ * http://sourceforge.net/projects/zbar
+ *------------------------------------------------------------------------*/
+
+#include "config.h"
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#ifdef _WIN32
+#include <fcntl.h>
+#include <io.h>
+#include <objbase.h>
+#endif
+#include <assert.h>
+
+#include <zbar.h>
+
+#ifdef ENABLE_NLS
+#include <libintl.h>
+#include <locale.h>
+#define _(string) gettext(string)
+#else
+#define _(string) string
+#endif
+
+#define N_(string) string
+
+#define BELL "\a"
+
+static const char *note_usage = N_(
+ "usage: zbarcam [options] [/dev/video?]\n"
+ "\n"
+ "scan and decode bar codes from a video stream\n"
+ "\n"
+ "options:\n"
+ " -h, --help display this help text\n"
+ " --version display version information and exit\n"
+ " -q, --quiet disable beep when symbol is decoded\n"
+ " -v, --verbose increase debug output level\n"
+ " --verbose=N set specific debug output level\n"
+ " --xml use XML output format\n"
+ " --raw output decoded symbol data without converting charsets\n"
+ " -1, --oneshot exit after scanning one bar code\n"
+ " --nodisplay disable video display window\n"
+ " --prescale=<W>x<H>\n"
+ " request alternate video image size from driver\n"
+ " -S<CONFIG>[=<VALUE>], --set <CONFIG>[=<VALUE>]\n"
+ " set decoder/scanner <CONFIG> to <VALUE> (or 1)\n"
+ /* FIXME overlay level */
+ "\n");
+
+#ifdef HAVE_DBUS
+static const char *note_usage2 =
+ N_(" --nodbus disable dbus message\n");
+#endif
+
+static const char *xml_head =
+ "<barcodes xmlns='http://zbar.sourceforge.net/2008/barcode'>"
+ "<source device='%s'>\n";
+static const char *xml_foot = "</source></barcodes>\n";
+
+static zbar_processor_t *proc;
+static int quiet = 0, oneshot = 0;
+static enum
+{
+ DEFAULT,
+ RAW,
+ XML
+} format = DEFAULT;
+
+static char *xml_buf = NULL;
+static unsigned xml_len = 0;
+
+static int usage(int rc)
+{
+ FILE *out = (rc) ? stderr : stdout;
+ fprintf(out, "%s", _(note_usage));
+#ifdef HAVE_DBUS
+ fprintf(out, "%s", _(note_usage2));
+#endif
+ return (rc);
+}
+
+static inline int parse_config(const char *cfgstr, int i, int n, char *arg)
+{
+ if (i >= n || !*cfgstr) {
+ fprintf(stderr, "ERROR: need argument for option: %s\n", arg);
+ return (1);
+ }
+
+ if (zbar_processor_parse_config(proc, cfgstr)) {
+ fprintf(stderr, "ERROR: invalid configuration setting: %s\n", cfgstr);
+ return (1);
+ }
+ return (0);
+}
+
+static void data_handler(zbar_image_t *img, const void *userdata)
+{
+ int n = 0;
+ const zbar_symbol_t *sym = zbar_image_first_symbol(img);
+ assert(sym);
+ for (; sym; sym = zbar_symbol_next(sym)) {
+ zbar_symbol_type_t type;
+ if (zbar_symbol_get_count(sym))
+ continue;
+
+ type = zbar_symbol_get_type(sym);
+ if (type == ZBAR_PARTIAL)
+ continue;
+
+ if (!format) {
+ printf("%s:", zbar_get_symbol_name(type));
+ if (fwrite(zbar_symbol_get_data(sym),
+ zbar_symbol_get_data_length(sym), 1, stdout) != 1)
+ continue;
+ } else if (format == RAW) {
+ if (fwrite(zbar_symbol_get_data(sym),
+ zbar_symbol_get_data_length(sym), 1, stdout) != 1)
+ continue;
+ } else if (format == XML) {
+ if (!n)
+ printf("<index num='%u'>\n", zbar_image_get_sequence(img));
+ zbar_symbol_xml(sym, &xml_buf, &xml_len);
+ if (fwrite(xml_buf, xml_len, 1, stdout) != 1)
+ continue;
+ }
+ n++;
+
+ if (oneshot) {
+ if (format != RAW)
+ printf("\n");
+ break;
+ } else
+ printf("\n");
+ }
+
+ if (format == XML && n)
+ printf("</index>\n");
+ fflush(stdout);
+
+ if (!quiet && n)
+ fprintf(stderr, BELL);
+}
+
+int main(int argc, const char *argv[])
+{
+ const char *video_device;
+ int display;
+ unsigned long infmt, outfmt;
+ int i, active;
+
+#ifdef ENABLE_NLS
+ setlocale(LC_ALL, "");
+ bindtextdomain(PACKAGE, LOCALEDIR);
+ textdomain(PACKAGE);
+#endif
+
+#ifdef DIRECTSHOW
+ HRESULT res = CoInitializeEx(NULL, COINIT_APARTMENTTHREADED);
+ if (FAILED(res)) {
+ fprintf(stderr, "ERROR: failed to initialize COM library\n");
+ return (1);
+ }
+#endif
+
+ /* setup zbar library standalone processor,
+ * threads will be used if available
+ */
+ proc = zbar_processor_create(1);
+ if (!proc) {
+ fprintf(stderr, "ERROR: unable to allocate memory?\n");
+ return (1);
+ }
+ zbar_processor_set_data_handler(proc, data_handler, NULL);
+
+ video_device = "";
+#ifdef HAVE_DBUS
+ int dbus = 1;
+#endif
+ display = 1;
+ infmt = 0, outfmt = 0;
+ for (i = 1; i < argc; i++) {
+ if (argv[i][0] != '-')
+ video_device = argv[i];
+ else if (argv[i][1] != '-') {
+ int j;
+ for (j = 1; argv[i][j]; j++) {
+ if (argv[i][j] == 'S') {
+ if (!argv[i][++j]) {
+ i++;
+ j = 0;
+ }
+ if (parse_config(&argv[i][j], i, argc, "-S"))
+ return (usage(1));
+ break;
+ }
+ switch (argv[i][j]) {
+ case 'h':
+ return (usage(0));
+ case 'v':
+ zbar_increase_verbosity();
+ break;
+ case 'q':
+ quiet = 1;
+ break;
+ case '1':
+ oneshot = 1;
+ break;
+ default:
+ fprintf(stderr, "ERROR: unknown bundled config: -%c\n\n",
+ argv[i][j]);
+ return (usage(1));
+ }
+ }
+ } else if (!argv[i][2]) {
+ if (i < argc - 1)
+ video_device = argv[argc - 1];
+ break;
+ } else if (!strcmp(argv[i], "--help"))
+ return (usage(0));
+ else if (!strcmp(argv[i], "--version"))
+ return (printf(PACKAGE_VERSION "\n") <= 0);
+ else if (!strcmp(argv[i], "--set")) {
+ i++;
+ if (parse_config(argv[i], i, argc, "--set"))
+ return (usage(1));
+ } else if (!strncmp(argv[i], "--set=", 6)) {
+ if (parse_config(&argv[i][6], i, argc, "--set="))
+ return (usage(1));
+ } else if (!strcmp(argv[i], "--quiet"))
+ quiet = 1;
+ else if (!strcmp(argv[i], "--oneshot"))
+ oneshot = 1;
+ else if (!strcmp(argv[i], "--xml"))
+ format = XML;
+ else if (!strcmp(argv[i], "--raw"))
+ format = RAW;
+ else if (!strcmp(argv[i], "--nodbus"))
+#ifdef HAVE_DBUS
+ dbus = 0;
+#else
+ ; /* silently ignore the option */
+#endif
+ else if (!strcmp(argv[i], "--nodisplay"))
+ display = 0;
+ else if (!strcmp(argv[i], "--verbose"))
+ zbar_increase_verbosity();
+ else if (!strncmp(argv[i], "--verbose=", 10))
+ zbar_set_verbosity(strtol(argv[i] + 10, NULL, 0));
+ else if (!strncmp(argv[i], "--prescale=", 11)) {
+ char *x = NULL;
+ long int w = strtol(argv[i] + 11, &x, 10);
+ long int h = 0;
+ if (x && *x == 'x')
+ h = strtol(x + 1, NULL, 10);
+ if (!w || !h || !x || *x != 'x') {
+ fprintf(stderr, "ERROR: invalid prescale: %s\n\n", argv[i]);
+ return (usage(1));
+ }
+ zbar_processor_request_size(proc, w, h);
+ } else if (!strncmp(argv[i], "--v4l=", 6)) {
+ long int v = strtol(argv[i] + 6, NULL, 0);
+ zbar_processor_request_interface(proc, v);
+ } else if (!strncmp(argv[i], "--iomode=", 9)) {
+ long int v = strtol(argv[i] + 9, NULL, 0);
+ zbar_processor_request_iomode(proc, v);
+ } else if (!strncmp(argv[i], "--infmt=", 8) && strlen(argv[i]) == 12)
+ infmt = (argv[i][8] | (argv[i][9] << 8) | (argv[i][10] << 16) |
+ (argv[i][11] << 24));
+ else if (!strncmp(argv[i], "--outfmt=", 9) && strlen(argv[i]) == 13)
+ outfmt = (argv[i][9] | (argv[i][10] << 8) | (argv[i][11] << 16) |
+ (argv[i][12] << 24));
+ else {
+ fprintf(stderr, "ERROR: unknown option argument: %s\n\n", argv[i]);
+ return (usage(1));
+ }
+ }
+
+ if (infmt || outfmt)
+ zbar_processor_force_format(proc, infmt, outfmt);
+
+#ifdef HAVE_DBUS
+ zbar_processor_request_dbus(proc, dbus);
+#endif
+
+ /* open video device, open window */
+ if (zbar_processor_init(proc, video_device, display) ||
+ /* show window */
+ (display && zbar_processor_set_visible(proc, 1)))
+ return (zbar_processor_error_spew(proc, 0));
+
+#ifdef _WIN32
+ if (format == XML || format == RAW) {
+ fflush(stdout);
+ if (_setmode(_fileno(stdout), _O_BINARY) == -1) {
+ fprintf(stderr, "ERROR: failed to set stdout mode: %i\n", errno);
+ return (1);
+ }
+ }
+#endif
+
+ if (format == XML) {
+ printf(xml_head, video_device);
+ fflush(stdout);
+ }
+
+ /* start video */
+ active = 1;
+ if (zbar_processor_set_active(proc, active))
+ return (zbar_processor_error_spew(proc, 0));
+
+ if (oneshot) {
+ if (zbar_process_one(proc, -1) < 0)
+ if (zbar_processor_get_error_code(proc) != ZBAR_ERR_CLOSED)
+ return zbar_processor_error_spew(proc, 0);
+ } else {
+ /* let the callback handle data */
+ int rc;
+ while ((rc = zbar_processor_user_wait(proc, -1)) >= 0) {
+ if (rc == 'q' || rc == 'Q')
+ break;
+ // HACK: controls are known on V4L2 by ID, not by name. This is also
+ // not compatible with other platforms
+ if (rc == 'b' || rc == 'B') {
+ int value;
+ zbar_processor_get_control(proc, "Brightness", &value);
+ zbar_processor_set_control(proc, "Brightness", ++value);
+ }
+ if (rc == 'n' || rc == 'N') {
+ int value;
+ zbar_processor_get_control(proc, "Brightness", &value);
+ zbar_processor_set_control(proc, "Brightness", --value);
+ }
+ if (rc == ' ') {
+ active = !active;
+ if (zbar_processor_set_active(proc, active))
+ return (zbar_processor_error_spew(proc, 0));
+ }
+ }
+
+ /* report any errors that aren't "window closed" */
+ if (rc && rc != 'q' && rc != 'Q' &&
+ zbar_processor_get_error_code(proc) != ZBAR_ERR_CLOSED)
+ return (zbar_processor_error_spew(proc, 0));
+ }
+
+ /* free resources (leak check) */
+ zbar_processor_destroy(proc);
+
+ if (format == XML) {
+ printf("%s", xml_foot);
+ fflush(stdout);
+ }
+ return (0);
+}
diff --git a/zbarcam/zbarcam.rc b/zbarcam/zbarcam.rc
new file mode 100644
index 0000000..f5e0800
--- /dev/null
+++ b/zbarcam/zbarcam.rc
@@ -0,0 +1,30 @@
+#include <config.h>
+#include <winver.h>
+
+VS_VERSION_INFO VERSIONINFO
+ FILEVERSION ZBAR_VERSION_MAJOR, ZBAR_VERSION_MINOR, ZBAR_VERSION_PATCH, 0
+ PRODUCTVERSION ZBAR_VERSION_MAJOR, ZBAR_VERSION_MINOR, ZBAR_VERSION_PATCH, 0
+ FILEOS VOS__WINDOWS32
+ FILETYPE VFT_APP
+{
+ BLOCK "StringFileInfo" {
+ BLOCK "040904E4" {
+ VALUE "ProductName", "ZBar Bar Code Reader"
+ VALUE "Company Name", "ZBar Bar Code Reader"
+ VALUE "InternalName", "zbarcam"
+ VALUE "OriginalFilename", "zbarcam.exe"
+
+ VALUE "FileVersion", PACKAGE_VERSION
+ VALUE "ProductVersion", PACKAGE_VERSION
+
+ VALUE "FileDescription", "Scan bar codes from video devices"
+
+ VALUE "LegalCopyright", "Copyright 2007-2010 (c) Jeff Brown <spadix@users.sourceforge.net>"
+ }
+ }
+ BLOCK "VarFileInfo" {
+ VALUE "Translation", 0x0409, 0x04e4
+ }
+}
+
+APP_ICON ICON "zbar.ico"