Update to the very latest version of zbar

zbar was using a 2010 snapshot of its hg tree.
Take a new snapshot to get zbar's improvements.

[Imported from Fedora 26 tree]
This commit is contained in:
Mauro Carvalho Chehab 2013-02-22 08:26:55 -03:00 committed by Mauro Carvalho Chehab
parent 1c1f76ea81
commit cd5b63e5b5
279 changed files with 27960 additions and 1666 deletions

View File

@ -7,7 +7,7 @@ aclocal.m4
configure
config
config.guess
config.h
config/config.h
config.h.in
config.log
config.status
@ -19,3 +19,18 @@ libtool
ltmain.sh
autom4te.cache
missing
python/MANIFEST
build
*.xcodeproj/*.mode1v3
*.xcodeproj/*.pbxuser
xcuserdata
contents.xcworkspacedata
.DS_Store
android/obj
*.class
*.dex
android/libs
android/examples/*/libs
android/*.zip
android/local.properties
android/examples/*/local.properties

18
.hgtags
View File

@ -9,3 +9,21 @@ f0aa6bf0cab7fda8725ce0da35d3e69473269c71 0.8
38265c7b4ad4dfafe7b5e9eae4bb0d43d68b4143 0.9
2dc2d73c468a032edc68a127e9ddbbfe5f520777 0.9
f3670ba47f2e070f4c43e97f4de3200903720e73 0.10
f3670ba47f2e070f4c43e97f4de3200903720e73 0.10
563557a923d0e23e36c81878d660aefc1c0fe3e7 0.10
b21098d27ff88c4f1a529fe0762f1cb307e04399 iPhoneSDK-0.1
b0bda6247b2fe4ffb52db89a776f91244f25d897 iPhoneSDK-0.1.1
d1655a680c3df68b3466d3b2c714f30af7223ec6 iPhoneSDK-0.1.2
4556c996acaaa6fcd5e8e9879f410f8120746e2b iPhoneSDK-1.0
12de07e51dce0d1cfc3e9699bbf9d5c8774a5371 iPhoneSDK-1.0.1
12de07e51dce0d1cfc3e9699bbf9d5c8774a5371 iPhoneSDK-1.0.1
2541a66ae7d64fbd923168ae677abb156021e88d iPhoneSDK-1.0.1
5e5060b563a1878ea297af5a50261d14cf1cb449 iPhoneSDK-1.1
f9e46865dbcebd04683ca7592ab32aeda615e772 iPhoneSDK-1.1.1
801318a6195060c31259da1f076ecc9a609616cc iPhoneSDK-1.1.2
4bbb4e2bdba8c41a282df7e65a02797250f44daa iPhoneSDK-1.1.3
1ad84c3c03252c366a82552fa952674ec593c73f iPhoneSDK-1.2
9e7bad13ae6a4b65e0f0964512f96284d37f0dc8 iPhoneSDK-1.2.1
146b857ff41ae462cc52f8dddf46d867763433a1 iPhoneSDK-1.2.2
9b946a7ead73ac99e121de2e7f495213cda88e6f AndroidSDK-0.1
5eb3c8786845fe3ad2c74f6a660e70176b88347f iPhoneSDK-1.3.1

View File

@ -1,4 +1,4 @@
The ZBar Bar Code Reader is Copyright (C) 2007-2009 Jeff Brown
The ZBar Bar Code Reader is Copyright (C) 2007-2011 Jeff Brown
<spadix@users.sourceforge.net>
The QR Code reader is Copyright (C) 1999-2009 Timothy B. Terriberry
<tterribe@xiph.org>

View File

@ -1,3 +1,95 @@
current:
* Codabar reliability enhancements
- fix missing check
- require minimum quality
- bump default uncertainty
* tweak Codabar bar/space ratio validation
* finish Codabar support for python, perl, java and iPhone interfaces
- reduce Codabar uncertainty to minimum
* add core support for Codabar symbology
- TBD: python, perl, java and iPhone interfaces
* fix v4l config and build variations (bug #3348888)
- thanks to jarekczek for reporting this!
- NB v4l1 removed from kernel as of 2.6.38
* fix missing python thread initialization (bug #3349199)
- thanks to jarekczek for reporting this problem!
* fix missing configure check for Python.h (bug #3092663)
- thanks to Zoltan Kovacs for reporting this problem!
* fix C++ wrapper missing Symbol.quality (bug #3076524)
- thanks to Rudy Melli for pointing this out!
* fix C++ wrapper bugs (bug #3396068)
- thanks to anotheruser1 for reporting this!
- add new C++ wrapper test
* fix avoid compositing ISBN10 data
* add support for GraphicsMagick as ImageMagick alternative
* mention xmlto in HACKING (patch #3297039)
- thanks to jarekczek for the patch!
* disable addons by default until synchronization with main symbol is working
* fix image scanner min quality filtering
* fix i25 buffer overrun corner case
* fix EAN addon enables
* fix zbarimg to accept autodetected stdin (lone dash)
* fix Qt 4.6.3 compilation error (patch #3178244)
- thanks to hrhristov for the patch!
* add Python Processor support for request_size interface
* fix Python Processor support for GIL, allowing asynchronous scanning
* fix jpeg decoder skip handling
- thanks to jarekczek for the patch!
* rename dprintf macro to avoid conflicts (patch #3128538)
- thanks to maurochehab for the patch!
* add support for EAN/UPC 2 and 5 digit add-on symbols
- deprecate original, unfinished add-on APIs
- add self-checking to test_decode
* fix support for GS1 AIs
- thanks to jockusch for a patch!
- add decoder/symbol "modifier" flags and config read access
- set flags or emit GS appropriately for Code 128 FNC1
- add iphone, java, perl, python bindings for modifiers and configs
* add support for Code 93 symbology
* add video size request to (Py)GTK widget (req #3034522)
- thanks to Jerome Charaoui for the patch!
* add support for GS1 DataBar Expanded (RSS Expanded) symbology
* add language bindings for DataBar
* add preliminary support for GS1 DataBar (RSS-14) symbology
* enhance decoder reliability (EAN, Code 39, Code 128)
- enhance decoder test
* fix documentation of command exit codes (bug #3017322)
* fix C++ video callback bug
- add C and C++ processor examples
* add per-symbology cache consistency
- reliable symbologies decode immediately by default
- no more need to disable cache with video
- also fix crop bugs w/video scanning
* add support for scanning partial images (cropping)
- update c++, python, perl, java bindings and tests
* fix couple of leaks
* remove doc hints about GFDL (bug #3004411)
- apply LGPL to API docs
* relax Code 39 width ratio checks
* core library portability improvements
- remove some unnecessary C99 syntax
- add configure checks for errno
- enhance C++ Symbol interface
* adjust Python module README (add examples and note DLL in path)
* fix QR Code missing from man pages (bug #2969857)
* cleanup decoder assertions and locking (bug #2966916)
* add Java interface to library via JNI
- add Java tools and JNI build tests to configure
- fix compiler warnings from binary output changes
* fix output of binary data in zbarimg and zbarcam
- thanks to fukuchi for a patch!
- add base64 format for binary xml output
* add coarse symbol orientation information (patch #2913094)
- thanks to Anssi for a patch!
- add decode direction feedback to decoder
- update C++, Python, Perl and ObjC wrappers
- add orientation to test suites
* fix inconsistent fourcc endian handling bugs (bug #2918994)
- thanks to jdccdevel for a patch!
- add fourcc conversion and parse interfaces to zbar.h
* report QR immediately for video (no inter-frame consistency check)
* add python distutils build infrastructure
version 0.10:
* hotfix add MinGW import lib to Windows installer
* attempt fix for Qt4 < 4.4

View File

@ -13,6 +13,12 @@ be fine):
GNU autoconf 2.61
GNU automake 1.10.1
GNU libtool 2.2.6
GNU gettext 0.18.1.1
GNU pkg-config 0.25
xmlto 0.0.20-5 (for docs building)
all above mentioned tools (except xmlto) must be installed in the same
prefix. mixing prefixes (i.g. /usr/bin and /usr/local/bin) may lead to
errors in configuration stages
when you're done hacking and want to make your patch, run:

View File

@ -1,6 +1,3 @@
AM_CPPFLAGS = -I$(srcdir)/include
AM_CFLAGS = -Wall -Wno-parentheses
AM_CXXFLAGS = $(AM_CFLAGS)
ACLOCAL_AMFLAGS = -I config
bin_PROGRAMS =
check_PROGRAMS =
@ -9,8 +6,10 @@ lib_LTLIBRARIES =
pyexec_LTLIBRARIES =
CLEANFILES =
DISTCLEANFILES =
MAINTAINERCLEANFILES =
BUILT_SOURCES =
EXTRA_DIST =
SUBDIRS = .
pkgconfigdir = $(libdir)/pkgconfig
pkgconfig_DATA = zbar.pc
@ -39,6 +38,9 @@ if HAVE_QT
include $(srcdir)/qt/Makefile.am.inc
pkgconfig_DATA += zbar-qt.pc
endif
if HAVE_JAVA
SUBDIRS += java
endif
if HAVE_NPAPI
include $(srcdir)/plugin/Makefile.am.inc
endif
@ -47,11 +49,8 @@ include $(srcdir)/doc/Makefile.am.inc
EXTRA_DIST += zbar.ico zbar.nsi
EXTRA_DIST += examples/upcrpc.pl examples/upcrpc.py examples/paginate.pl \
examples/barcode.png examples/processor.pl examples/processor.py \
examples/read_one.py examples/read_one.pl \
examples/scan_image.c examples/scan_image.cpp examples/scan_image.pl \
examples/scan_image.py examples/scan_image.vcproj
EXTRA_DIST += examples/barcode.png examples/upcrpc.py examples/upcrpc.pl \
examples/scan_image.c examples/scan_image.cpp examples/scan_image.vcproj
EXTRA_DIST += perl/MANIFEST perl/README perl/Changes perl/COPYING.LIB \
perl/Makefile.PL perl/typemap perl/ZBar.xs perl/ppport.h \

6
README
View File

@ -4,9 +4,9 @@ ZBAR BAR CODE READER
ZBar Bar Code Reader is an open source software suite for reading bar
codes from various sources, such as video streams, image files and raw
intensity sensors. It supports EAN-13/UPC-A, UPC-E, EAN-8, Code 128,
Code 39, Interleaved 2 of 5 and QR Code. Included with the library
are basic applications for decoding captured bar code images and using
a video device (eg, webcam) as a bar code scanner. For application
Code 39, Codabar, Interleaved 2 of 5 and QR Code. Included with the
library are basic applications for decoding captured bar code images and
using a video device (eg, webcam) as a bar code scanner. For application
developers, language bindings are included for C, C++, Python and Perl
as well as GUI widgets for Qt, GTK and PyGTK.

View File

@ -3,8 +3,8 @@ ZBAR BAR CODE READER
ZBar Bar Code Reader is an open source software suite for reading bar codes
from various sources, such as video streams, image files and raw intensity
sensors. It supports EAN-13/UPC-A, UPC-E, EAN-8, Code 128, Code 39,
Interleaved 2 of 5 and QR Code. Included with the library are basic
sensors. It supports EAN-13/UPC-A, UPC-E, EAN-8, Code 128, Code 93, Code 39,
Codabar, Interleaved 2 of 5 and QR Code. Included with the library are basic
applications for decoding captured bar code images and using a video device
(eg, webcam) as a bar code scanner. For application developers, language
bindings are included for C, C++, Python and Perl as well as GUI widgets for

1
TODO
View File

@ -25,7 +25,6 @@ symbologies:
* Code 39, i25 optional features (check digit and ASCII escapes)
* handle Code 128 function characters (FNC1-4)
* Code 128 trailing quiet zone checks
* finish addon decoding
decoder:
* start/stop/abort and location detail APIs (PDF417, OMR)

View File

@ -0,0 +1,15 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="net.sourceforge.zbar.android"
android:versionCode="1"
android:versionName="1.0">
<application android:label="@string/app_name" >
<activity android:name="ACTIVITY_ENTRY_NAME"
android:label="@string/app_name">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>
</manifest>

2
android/ChangeLog Normal file
View File

@ -0,0 +1,2 @@
version 0.1:
* Add initial support for Android platform

112
android/README Normal file
View File

@ -0,0 +1,112 @@
ZBar Android SDK
================
ZBar Bar Code Reader is an open source software suite for reading bar
codes from various sources, such as video streams, image files and raw
intensity sensors. It supports EAN-13/UPC-A, UPC-E, EAN-8, Code 128,
Code 93, Code 39, Codabar, Interleaved 2 of 5, QR Code and
DataBar. These are the JNI wrappers for developing the library on
Android platform.
Check the ZBar home page for the latest release, mailing lists, etc.
http://zbar.sourceforge.net/
Copyright and License
---------------------
Licensed under the GNU Lesser General Public License, version 2.1.
http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt
Copyright 2008-2012 © Jeff Brown <spadix@users.sourceforge.net> et al
The Android distribution also includes pre-compiled binaries of
supporting libaries, for which copyright, license and source code
locations are as follows:
* The GNU libiconv character set conversion library
Copyright (C) 1999-2011 Free Software Foundation, Inc.
This distribution includes GNU libiconv version 1.14, licensed under
the LGPL version 2. The source code is available from
http://www.gnu.org/software/libiconv
See included files COPYING and LICENSE for details.
Installation
------------
After downloading the ZBar-Android-Lib-<version>.zip file, you need to
unzip the file and add it to your Android project. Unzip the file
using your favorite method (ie: command-line, finder, windows
explorer...)
Follow one of the two options.
Option 1 - via command line
cd <android project>
cp -r ZBar-Android-SDK-<version>/libs .
Option 2 - via Eclipse
Right click on Android Project
Select "Import" -> "File System"
Select "Browse" (next to "From directory File" and select the
ZBar-Android-SDK-<verion>/libs directory and click "Open".
Click the check box next to "libs" and the "Options" "Create top-level folder"
check box (below).
Then click "Finish".
You should then see a "libs" folder under your project.
Building
--------
Via Eclipse
You have to add the zbar.jar file to your build path
1) select zbar.jar under libs
2) right-click, select "Build Path" -> "Add to Build Path"
Via command-line
You are all set; ant will automatcially find jar files under the "libs"
subdirectory.
Documentation
-------------
TDB
Examples
--------
You should be able to open and build the examples directly from the
unzipped directory. You will need to run the android tools to setup
the local.properties file which sets sdk.dir.
1) cd <unzip dir>/examples/CameraTest
2) android update project --path .
3) ant debug install
If you have problems with this, please create a new Android project
and copy the necessary files from the examples.
examples/CameraTest is a simple demonstration of how to integrate the
ZBar image scanner with the camera.
Manually building ZBar JNI library
----------------------------------
First download and unzip the iconv library source from
http://www.gnu.org/software/libiconv/
Then kick off the build from the ZBar android directory. You will
need to run the android tools to setup the local.properties file which
setups sdk.dir.
1) cd <zbar project>/android
2) android update project --path .
3) ant -Dndk.dir=<NDK path> -Diconv.src=<iconv library src> zbar-all
This will rebuild all source files, create zbar.jar and
ZBarAndroidSDK.zip file (which bundles the jar and shared
libraries). From here, you can follow the steps for "Integrating ZBar
JNI library in Android project".
To clean run:
ant -Dndk.dir=<NDK path> zbar-clean
See build-ndk.xml for additional target options.

17
android/ant.properties Normal file
View File

@ -0,0 +1,17 @@
# This file is used to override default values used by the Ant build system.
#
# This file must be checked in Version Control Systems, as it is
# integral to the build system of your project.
# This file is only used by the Ant script.
# You can use this to override default values such as
# 'source.dir' for the location of your java source folder and
# 'out.dir' for the location of your output folder.
# You can also use it define how the release builds are signed by declaring
# the following properties:
# 'key.store' for the location of your keystore and
# 'key.alias' for the name of the key to use.
# The password will be asked during the build when you use the 'release' target.

66
android/build-ndk.xml Normal file
View File

@ -0,0 +1,66 @@
<!--
Ant build file to compile the ZBar JNI files using Android NDK tool
targets:
zbar-clean - removes build generated files, build dir, jar and zip files
zbar-ndk-build - builds the zbarjni and iconv shared libraries
zbar-compile - builds the zbar java files
zbar-jar - builds and jars the zbar java files
zbar-zip - Creates ZBarAndroidSDK-x.y.zip of jar, .so, etc
zbar-all - performs all the above :)
-->
<project name="zbar">
<property name="project.name" value="zbar" />
<property name="project.sdk.name" value="ZBarAndroidSDK" />
<target name="zbar-clean">
<delete dir="../java/build"/>
<delete file="libs/${project.name}.jar"/>
<delete file="${ant.project.name}.zip"/>
<exec executable="${ndk.dir}/ndk-build" failonerror="true">
<arg value="clean"/>
</exec>
</target>
<target name="zbar-ndk-build">
<exec executable="${ndk.dir}/ndk-build" failonerror="true">
<arg value="ICONV_SRC=${iconv.src}" />
</exec>
</target>
<target name="zbar-compile" depends="zbar-ndk-build">
<mkdir dir="../java/build" />
<javac srcdir="../java/net" destdir="../java/build" />
</target>
<target name="zbar-jar" depends="zbar-compile">
<jar destfile="libs/${project.name}.jar" basedir="../java/build">
</jar>
</target>
<target name="zbar-zip">
<if><condition><not><isset property="version"/></not></condition><then>
<property name="version" value="0.2" />
</then></if>
<zip destfile="${project.sdk.name}-${version}.zip" >
<zipfileset dir="../" prefix="${project.sdk.name}-${version}" includes="COPYING, LICENSE"/>
<zipfileset dir="." prefix="${project.sdk.name}-${version}" includes="README"/>
<zipfileset dir="libs" prefix="${project.sdk.name}-${version}/libs"/>
<zipfileset dir="examples" prefix="${project.sdk.name}-${version}/examples"/>
<zipfileset dir="libs" prefix="${project.sdk.name}-${version}/examples/CameraTest/libs"/>
</zip>
</target>
<target name="zbar-all" depends="zbar-jar">
<if><condition><not><isset property="version"/></not></condition><then>
<property name="version" value="0.2" />
</then></if>
<zip destfile="${project.sdk.name}-${version}.zip" >
<zipfileset dir="../" prefix="${project.sdk.name}-${version}" includes="COPYING, LICENSE"/>
<zipfileset dir="." prefix="${project.sdk.name}-${version}" includes="README"/>
<zipfileset dir="libs" prefix="${project.sdk.name}-${version}/libs"/>
<zipfileset dir="examples" prefix="${project.sdk.name}-${version}/examples"/>
<zipfileset dir="libs" prefix="${project.sdk.name}-${version}/examples/CameraTest/libs"/>
</zip>
</target>
</project>

86
android/build.xml Normal file
View File

@ -0,0 +1,86 @@
<?xml version="1.0" encoding="UTF-8"?>
<project name="ZBarAndroidSDK" default="help">
<!-- The local.properties file is created and updated by the 'android' tool.
It contains the path to the SDK. It should *NOT* be checked into
Version Control Systems. -->
<property file="local.properties" />
<!-- The ant.properties file can be created by you. It is only edited by the
'android' tool to add properties to it.
This is the place to change some Ant specific build properties.
Here are some properties you may want to change/update:
source.dir
The name of the source directory. Default is 'src'.
out.dir
The name of the output directory. Default is 'bin'.
For other overridable properties, look at the beginning of the rules
files in the SDK, at tools/ant/build.xml
Properties related to the SDK location or the project target should
be updated using the 'android' tool with the 'update' action.
This file is an integral part of the build system for your
application and should be checked into Version Control Systems.
-->
<property file="ant.properties" />
<!-- The project.properties file is created and updated by the 'android'
tool, as well as ADT.
This contains project specific properties such as project target, and library
dependencies. Lower level build properties are stored in ant.properties
(or in .classpath for Eclipse projects).
This file is an integral part of the build system for your
application and should be checked into Version Control Systems. -->
<loadproperties srcFile="project.properties" />
<!-- quick check on sdk.dir -->
<fail
message="sdk.dir is missing. Make sure to generate local.properties using 'android update project' or to inject it through an env var"
unless="sdk.dir"
/>
<!-- extension targets. Uncomment the ones where you want to do custom work
in between standard targets -->
<!--
<target name="-pre-build">
</target>
<target name="-pre-compile">
</target>
/* This is typically used for code obfuscation.
Compiled code location: ${out.classes.absolute.dir}
If this is not done in place, override ${out.dex.input.absolute.dir} */
<target name="-post-compile">
<copy file="${out.absolute.dir}/classes.jar" tofile="${jar.libs.dir}/zbar_android.jar" />
</target>
-->
<!-- Import the actual build file.
To customize existing targets, there are two options:
- Customize only one target:
- copy/paste the target into this file, *before* the
<import> task.
- customize it to your needs.
- Customize the whole content of build.xml
- copy/paste the content of the rules files (minus the top node)
into this file, replacing the <import> task.
- customize to your needs.
***********************
****** IMPORTANT ******
***********************
In all cases you must update the value of version-tag below to read 'custom' instead of an integer,
in order to avoid having your file be overridden by tools such as "android update project"
-->
<!-- version-tag: 1 -->
<import file="build-ndk.xml" />
<import file="${sdk.dir}/tools/ant/build.xml" />
</project>

View File

@ -0,0 +1,19 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="net.sourceforge.zbar.android.CameraTest"
android:versionCode="1"
android:versionName="1.0">
<uses-sdk android:minSdkVersion="8" />
<uses-permission android:name="android.permission.CAMERA" />
<uses-feature android:name="android.hardware.camera" />
<uses-feature android:name="android.hardware.camera.autofocus" />
<application android:label="@string/app_name" >
<activity android:name="CameraTestActivity"
android:label="@string/app_name">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>
</manifest>

View File

@ -0,0 +1,17 @@
# This file is used to override default values used by the Ant build system.
#
# This file must be checked in Version Control Systems, as it is
# integral to the build system of your project.
# This file is only used by the Ant script.
# You can use this to override default values such as
# 'source.dir' for the location of your java source folder and
# 'out.dir' for the location of your output folder.
# You can also use it define how the release builds are signed by declaring
# the following properties:
# 'key.store' for the location of your keystore and
# 'key.alias' for the name of the key to use.
# The password will be asked during the build when you use the 'release' target.

View File

@ -0,0 +1,85 @@
<?xml version="1.0" encoding="UTF-8"?>
<project name="CameraTest" default="help">
<!-- The local.properties file is created and updated by the 'android' tool.
It contains the path to the SDK. It should *NOT* be checked into
Version Control Systems. -->
<property file="local.properties" />
<!-- The ant.properties file can be created by you. It is only edited by the
'android' tool to add properties to it.
This is the place to change some Ant specific build properties.
Here are some properties you may want to change/update:
source.dir
The name of the source directory. Default is 'src'.
out.dir
The name of the output directory. Default is 'bin'.
For other overridable properties, look at the beginning of the rules
files in the SDK, at tools/ant/build.xml
Properties related to the SDK location or the project target should
be updated using the 'android' tool with the 'update' action.
This file is an integral part of the build system for your
application and should be checked into Version Control Systems.
-->
<property file="ant.properties" />
<!-- The project.properties file is created and updated by the 'android'
tool, as well as ADT.
This contains project specific properties such as project target, and library
dependencies. Lower level build properties are stored in ant.properties
(or in .classpath for Eclipse projects).
This file is an integral part of the build system for your
application and should be checked into Version Control Systems. -->
<loadproperties srcFile="project.properties" />
<!-- quick check on sdk.dir -->
<fail
message="sdk.dir is missing. Make sure to generate local.properties using 'android update project' or to inject it through an env var"
unless="sdk.dir"
/>
<!-- extension targets. Uncomment the ones where you want to do custom work
in between standard targets -->
<!--
<target name="-pre-build">
</target>
<target name="-pre-compile">
</target>
/* This is typically used for code obfuscation.
Compiled code location: ${out.classes.absolute.dir}
If this is not done in place, override ${out.dex.input.absolute.dir} */
<target name="-post-compile">
</target>
-->
<!-- Import the actual build file.
To customize existing targets, there are two options:
- Customize only one target:
- copy/paste the target into this file, *before* the
<import> task.
- customize it to your needs.
- Customize the whole content of build.xml
- copy/paste the content of the rules files (minus the top node)
into this file, replacing the <import> task.
- customize to your needs.
***********************
****** IMPORTANT ******
***********************
In all cases you must update the value of version-tag below to read 'custom' instead of an integer,
in order to avoid having your file be overridden by tools such as "android update project"
-->
<!-- version-tag: 1 -->
<import file="${sdk.dir}/tools/ant/build.xml" />
</project>

View File

@ -0,0 +1,40 @@
-optimizationpasses 5
-dontusemixedcaseclassnames
-dontskipnonpubliclibraryclasses
-dontpreverify
-verbose
-optimizations !code/simplification/arithmetic,!field/*,!class/merging/*
-keep public class * extends android.app.Activity
-keep public class * extends android.app.Application
-keep public class * extends android.app.Service
-keep public class * extends android.content.BroadcastReceiver
-keep public class * extends android.content.ContentProvider
-keep public class * extends android.app.backup.BackupAgentHelper
-keep public class * extends android.preference.Preference
-keep public class com.android.vending.licensing.ILicensingService
-keepclasseswithmembernames class * {
native <methods>;
}
-keepclasseswithmembers class * {
public <init>(android.content.Context, android.util.AttributeSet);
}
-keepclasseswithmembers class * {
public <init>(android.content.Context, android.util.AttributeSet, int);
}
-keepclassmembers class * extends android.app.Activity {
public void *(android.view.View);
}
-keepclassmembers enum * {
public static **[] values();
public static ** valueOf(java.lang.String);
}
-keep class * implements android.os.Parcelable {
public static final android.os.Parcelable$Creator *;
}

View File

@ -0,0 +1,11 @@
# This file is automatically generated by Android Tools.
# Do not modify this file -- YOUR CHANGES WILL BE ERASED!
#
# This file must be checked in Version Control Systems.
#
# To customize properties used by the Ant build system use,
# "ant.properties", and override values to adapt the script to your
# project structure.
# Project target.
target=android-15

View File

@ -0,0 +1,28 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent">
<FrameLayout
android:id="@+id/cameraPreview"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_weight="1"
/>
<TextView
android:id="@+id/scanText"
android:text="Scanning..."
android:layout_height="wrap_content"
android:layout_width="match_parent">
</TextView>
<Button
android:id="@+id/ScanButton"
android:text="Scan"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
/>
</LinearLayout>

View File

@ -0,0 +1,4 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<string name="app_name">ZBar CameraTest</string>
</resources>

View File

@ -0,0 +1,108 @@
/*
* Barebones implementation of displaying camera preview.
*
* Created by lisah0 on 2012-02-24
*/
package net.sourceforge.zbar.android.CameraTest;
import java.io.IOException;
import android.app.Activity;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.view.Surface;
import android.view.SurfaceView;
import android.view.SurfaceHolder;
import android.content.Context;
import android.hardware.Camera;
import android.hardware.Camera.PreviewCallback;
import android.hardware.Camera.AutoFocusCallback;
import android.hardware.Camera.Parameters;
/** A basic Camera preview class */
public class CameraPreview extends SurfaceView implements SurfaceHolder.Callback {
private SurfaceHolder mHolder;
private Camera mCamera;
private PreviewCallback previewCallback;
private AutoFocusCallback autoFocusCallback;
public CameraPreview(Context context, Camera camera,
PreviewCallback previewCb,
AutoFocusCallback autoFocusCb) {
super(context);
mCamera = camera;
previewCallback = previewCb;
autoFocusCallback = autoFocusCb;
/*
* Set camera to continuous focus if supported, otherwise use
* software auto-focus. Only works for API level >=9.
*/
/*
Camera.Parameters parameters = camera.getParameters();
for (String f : parameters.getSupportedFocusModes()) {
if (f == Parameters.FOCUS_MODE_CONTINUOUS_PICTURE) {
mCamera.setFocusMode(Parameters.FOCUS_MODE_CONTINUOUS_PICTURE);
autoFocusCallback = null;
break;
}
}
*/
// Install a SurfaceHolder.Callback so we get notified when the
// underlying surface is created and destroyed.
mHolder = getHolder();
mHolder.addCallback(this);
// deprecated setting, but required on Android versions prior to 3.0
mHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
}
public void surfaceCreated(SurfaceHolder holder) {
// The Surface has been created, now tell the camera where to draw the preview.
try {
mCamera.setPreviewDisplay(holder);
} catch (IOException e) {
Log.d("DBG", "Error setting camera preview: " + e.getMessage());
}
}
public void surfaceDestroyed(SurfaceHolder holder) {
// Camera preview released in activity
}
public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
/*
* If your preview can change or rotate, take care of those events here.
* Make sure to stop the preview before resizing or reformatting it.
*/
if (mHolder.getSurface() == null){
// preview surface does not exist
return;
}
// stop preview before making changes
try {
mCamera.stopPreview();
} catch (Exception e){
// ignore: tried to stop a non-existent preview
}
try {
// Hard code camera surface rotation 90 degs to match Activity view in portrait
mCamera.setDisplayOrientation(90);
mCamera.setPreviewDisplay(mHolder);
mCamera.setPreviewCallback(previewCallback);
mCamera.startPreview();
mCamera.autoFocus(autoFocusCallback);
} catch (Exception e){
Log.d("DBG", "Error starting camera preview: " + e.getMessage());
}
}
}

View File

@ -0,0 +1,155 @@
/*
* Basic no frills app which integrates the ZBar barcode scanner with
* the camera.
*
* Created by lisah0 on 2012-02-24
*/
package net.sourceforge.zbar.android.CameraTest;
import net.sourceforge.zbar.android.CameraTest.CameraPreview;
import android.app.Activity;
import android.content.pm.ActivityInfo;
import android.os.Bundle;
import android.os.Handler;
import android.util.Log;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.Window;
import android.widget.FrameLayout;
import android.widget.Button;
import android.hardware.Camera;
import android.hardware.Camera.PreviewCallback;
import android.hardware.Camera.AutoFocusCallback;
import android.hardware.Camera.Parameters;
import android.hardware.Camera.Size;
import android.widget.TextView;
import android.graphics.ImageFormat;
/* Import ZBar Class files */
import net.sourceforge.zbar.ImageScanner;
import net.sourceforge.zbar.Image;
import net.sourceforge.zbar.Symbol;
import net.sourceforge.zbar.SymbolSet;
import net.sourceforge.zbar.Config;
public class CameraTestActivity extends Activity
{
private Camera mCamera;
private CameraPreview mPreview;
private Handler autoFocusHandler;
TextView scanText;
Button scanButton;
ImageScanner scanner;
private boolean barcodeScanned = false;
private boolean previewing = true;
static {
System.loadLibrary("iconv");
}
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);
autoFocusHandler = new Handler();
mCamera = getCameraInstance();
/* Instance barcode scanner */
scanner = new ImageScanner();
scanner.setConfig(0, Config.X_DENSITY, 3);
scanner.setConfig(0, Config.Y_DENSITY, 3);
mPreview = new CameraPreview(this, mCamera, previewCb, autoFocusCB);
FrameLayout preview = (FrameLayout)findViewById(R.id.cameraPreview);
preview.addView(mPreview);
scanText = (TextView)findViewById(R.id.scanText);
scanButton = (Button)findViewById(R.id.ScanButton);
scanButton.setOnClickListener(new OnClickListener() {
public void onClick(View v) {
if (barcodeScanned) {
barcodeScanned = false;
scanText.setText("Scanning...");
mCamera.setPreviewCallback(previewCb);
mCamera.startPreview();
previewing = true;
mCamera.autoFocus(autoFocusCB);
}
}
});
}
public void onPause() {
super.onPause();
releaseCamera();
}
/** A safe way to get an instance of the Camera object. */
public static Camera getCameraInstance(){
Camera c = null;
try {
c = Camera.open();
} catch (Exception e){
}
return c;
}
private void releaseCamera() {
if (mCamera != null) {
previewing = false;
mCamera.setPreviewCallback(null);
mCamera.release();
mCamera = null;
}
}
private Runnable doAutoFocus = new Runnable() {
public void run() {
if (previewing)
mCamera.autoFocus(autoFocusCB);
}
};
PreviewCallback previewCb = new PreviewCallback() {
public void onPreviewFrame(byte[] data, Camera camera) {
Camera.Parameters parameters = camera.getParameters();
Size size = parameters.getPreviewSize();
Image barcode = new Image(size.width, size.height, "Y800");
barcode.setData(data);
int result = scanner.scanImage(barcode);
if (result != 0) {
previewing = false;
mCamera.setPreviewCallback(null);
mCamera.stopPreview();
SymbolSet syms = scanner.getResults();
for (Symbol sym : syms) {
scanText.setText("barcode result " + sym.getData());
barcodeScanned = true;
}
}
}
};
// Mimic continuous auto-focusing
AutoFocusCallback autoFocusCB = new AutoFocusCallback() {
public void onAutoFocus(boolean success, Camera camera) {
autoFocusHandler.postDelayed(doAutoFocus, 1000);
}
};
}

76
android/jni/Android.mk Normal file
View File

@ -0,0 +1,76 @@
#
# Android NDK makefile
#
# build - <ndk path>/ndk-build ICONV_SRC=<iconv library src>
# clean - <ndk path>/ndk-build clean
#
MY_LOCAL_PATH := $(call my-dir)
# libiconv
include $(CLEAR_VARS)
LOCAL_PATH := $(ICONV_SRC)
LOCAL_MODULE := libiconv
LOCAL_CFLAGS := \
-Wno-multichar \
-D_ANDROID \
-DLIBDIR="c" \
-DBUILDING_LIBICONV \
-DBUILDING_LIBCHARSET \
-DIN_LIBRARY
LOCAL_SRC_FILES := \
lib/iconv.c \
libcharset/lib/localcharset.c \
lib/relocatable.c
LOCAL_C_INCLUDES := \
$(ICONV_SRC)/include \
$(ICONV_SRC)/libcharset \
$(ICONV_SRC)/libcharset/include
include $(BUILD_SHARED_LIBRARY)
LOCAL_LDLIBS := -llog -lcharset
# libzbarjni
include $(CLEAR_VARS)
LOCAL_PATH := $(MY_LOCAL_PATH)
LOCAL_MODULE := zbarjni
LOCAL_SRC_FILES := ../../java/zbarjni.c \
../../zbar/img_scanner.c \
../../zbar/decoder.c \
../../zbar/image.c \
../../zbar/symbol.c \
../../zbar/convert.c \
../../zbar/config.c \
../../zbar/scanner.c \
../../zbar/error.c \
../../zbar/refcnt.c \
../../zbar/video.c \
../../zbar/video/null.c \
../../zbar/decoder/code128.c \
../../zbar/decoder/code39.c \
../../zbar/decoder/code93.c \
../../zbar/decoder/codabar.c \
../../zbar/decoder/databar.c \
../../zbar/decoder/ean.c \
../../zbar/decoder/i25.c \
../../zbar/decoder/qr_finder.c \
../../zbar/qrcode/bch15_5.c \
../../zbar/qrcode/binarize.c \
../../zbar/qrcode/isaac.c \
../../zbar/qrcode/qrdec.c \
../../zbar/qrcode/qrdectxt.c \
../../zbar/qrcode/rs.c \
../../zbar/qrcode/util.c
LOCAL_C_INCLUDES := ../include \
../zbar \
$(ICONV_SRC)/include
LOCAL_SHARED_LIBRARIES := libiconv
include $(BUILD_SHARED_LIBRARY)

View File

@ -0,0 +1 @@
APP_ABI := armeabi armeabi-v7a x86

236
android/jni/config.h Normal file
View File

@ -0,0 +1,236 @@
/* manually customized for iPhone platform */
#define HAVE_LANGINFO_CODESET 0
/* whether to build support for Code 128 symbology */
#define ENABLE_CODE128 1
/* whether to build support for Code 93 symbology */
#define ENABLE_CODE93 1
/* whether to build support for Code 39 symbology */
#define ENABLE_CODE39 1
/* whether to build support for Codabar symbology */
#define ENABLE_CODABAR 1
/* whether to build support for DataBar symbology */
#define ENABLE_DATABAR 1
/* whether to build support for EAN symbologies */
#define ENABLE_EAN 1
/* whether to build support for Interleaved 2 of 5 symbology */
#define ENABLE_I25 1
/* whether to build support for PDF417 symbology */
#undef ENABLE_PDF417
/* whether to build support for QR Code */
#define ENABLE_QRCODE 1
/* Define to 1 if you have the `atexit' function. */
#undef HAVE_ATEXIT
/* Define to 1 if you have the <dlfcn.h> header file. */
#undef HAVE_DLFCN_H
/* Define to 1 if you have the <fcntl.h> header file. */
#undef HAVE_FCNTL_H
/* Define to 1 if you have the <features.h> header file. */
#undef HAVE_FEATURES_H
/* Define to 1 if you have the `getpagesize' function. */
#undef HAVE_GETPAGESIZE
/* Define if you have the iconv() function and it works. */
#undef HAVE_ICONV
/* Define to 1 if you have the <inttypes.h> header file. */
#define HAVE_INTTYPES_H 1
/* Define to 1 if you have the <jpeglib.h> header file. */
#undef HAVE_JPEGLIB_H
/* Define to 1 if you have the `jpeg' library (-ljpeg). */
#undef HAVE_LIBJPEG
/* Define to 1 if you have the `pthread' library (-lpthread). */
#undef HAVE_LIBPTHREAD
/* Define to 1 if you have the <linux/videodev2.h> header file. */
#undef HAVE_LINUX_VIDEODEV2_H
/* Define to 1 if you have the <linux/videodev.h> header file. */
#undef HAVE_LINUX_VIDEODEV_H
/* Define to 1 if you have the <memory.h> header file. */
#undef HAVE_MEMORY_H
/* Define to 1 if you have the `memset' function. */
#define HAVE_MEMSET 1
/* Define to 1 if you have a working `mmap' system call. */
#undef HAVE_MMAP
/* Define to 1 if you have the <poll.h> header file. */
#undef HAVE_POLL_H
/* Define to 1 if you have the <pthread.h> header file. */
#undef HAVE_PTHREAD_H
/* Define to 1 if you have the `setenv' function. */
#undef HAVE_SETENV
/* Define to 1 if you have the <stdint.h> header file. */
#define HAVE_STDINT_H 1
/* Define to 1 if you have the <stdlib.h> header file. */
#define HAVE_STDLIB_H 1
/* Define to 1 if you have the <strings.h> header file. */
#define HAVE_STRINGS_H 1
/* Define to 1 if you have the <string.h> header file. */
#define HAVE_STRING_H 1
/* Define to 1 if you have the <sys/ioctl.h> header file. */
#undef HAVE_SYS_IOCTL_H
/* Define to 1 if you have the <sys/ipc.h> header file. */
#undef HAVE_SYS_IPC_H
/* Define to 1 if you have the <sys/mman.h> header file. */
#undef HAVE_SYS_MMAN_H
/* Define to 1 if you have the <sys/shm.h> header file. */
#undef HAVE_SYS_SHM_H
/* Define to 1 if you have the <sys/stat.h> header file. */
#define HAVE_SYS_STAT_H 1
/* Define to 1 if you have the <sys/times.h> header file. */
#define HAVE_SYS_TIMES_H 1
/* Define to 1 if you have the <sys/time.h> header file. */
#define HAVE_SYS_TIME_H 1
/* Define to 1 if you have the <sys/types.h> header file. */
#define HAVE_SYS_TYPES_H 1
/* Define to 1 if the system has the type `uintptr_t'. */
#define HAVE_UINTPTR_T 1
/* Define to 1 if you have the <unistd.h> header file. */
#define HAVE_UNISTD_H 1
/* Define to 1 if you have the <vfw.h> header file. */
#undef HAVE_VFW_H
/* Define to 1 if you have the <X11/extensions/XShm.h> header file. */
#undef HAVE_X11_EXTENSIONS_XSHM_H
/* Define to 1 if you have the <X11/extensions/Xvlib.h> header file. */
#undef HAVE_X11_EXTENSIONS_XVLIB_H
/* Define as const if the declaration of iconv() needs const. */
#undef ICONV_CONST
/* Library major version */
#define LIB_VERSION_MAJOR 0
/* Library minor version */
#define LIB_VERSION_MINOR 2
/* Library revision */
#define LIB_VERSION_REVISION 0
/* Define to the sub-directory in which libtool stores uninstalled libraries.
*/
#undef LT_OBJDIR
/* Define to 1 if assertions should be disabled. */
//#undef NDEBUG
/* Define to 1 if your C compiler doesn't accept -c and -o together. */
#undef NO_MINUS_C_MINUS_O
/* Name of package */
#define PACKAGE "zbar"
/* Define to the address where bug reports for this package should be sent. */
#define PACKAGE_BUGREPORT "spadix@users.sourceforge.net"
/* Define to the full name of this package. */
#define PACKAGE_NAME "zbar"
/* Define to the full name and version of this package. */
#define PACKAGE_STRING "zbar 0.10"
/* Define to the one symbol short name of this package. */
#define PACKAGE_TARNAME "zbar"
/* Define to the version of this package. */
#define PACKAGE_VERSION "0.10"
/* Define to 1 if you have the ANSI C header files. */
#define STDC_HEADERS 1
/* Version number of package */
#define VERSION "0.10"
/* Define to 1 if the X Window System is missing or not being used. */
#define X_DISPLAY_MISSING 1
/* Program major version (before the '.') as a number */
#define ZBAR_VERSION_MAJOR 0
/* Program minor version (after '.') as a number */
#define ZBAR_VERSION_MINOR 10
/* Define for Solaris 2.5.1 so the uint32_t typedef from <sys/synch.h>,
<pthread.h>, or <semaphore.h> is not used. If the typedef were allowed, the
#define below would cause a syntax error. */
#undef _UINT32_T
/* Define for Solaris 2.5.1 so the uint8_t typedef from <sys/synch.h>,
<pthread.h>, or <semaphore.h> is not used. If the typedef were allowed, the
#define below would cause a syntax error. */
#undef _UINT8_T
/* Minimum Windows API version */
#undef _WIN32_WINNT
/* used only for pthread debug attributes */
#undef __USE_UNIX98
/* Define to empty if `const' does not conform to ANSI C. */
#undef const
/* Define to `__inline__' or `__inline' if that's what the C compiler
calls it, or to nothing if 'inline' is not supported under any name. */
#ifndef __cplusplus
#undef inline
#endif
/* Define to the type of a signed integer type of width exactly 32 bits if
such a type exists and the standard includes do not define it. */
#undef int32_t
/* Define to the type of an unsigned integer type of width exactly 32 bits if
such a type exists and the standard includes do not define it. */
#undef uint32_t
/* Define to the type of an unsigned integer type of width exactly 8 bits if
such a type exists and the standard includes do not define it. */
#undef uint8_t
/* Define to the type of an unsigned integer type wide enough to hold a
pointer, if such a type exists, and if the system does not define it. */
#undef uintptr_t
#ifndef X_DISPLAY_MISSING
# define HAVE_X
#endif

40
android/proguard.cfg Normal file
View File

@ -0,0 +1,40 @@
-optimizationpasses 5
-dontusemixedcaseclassnames
-dontskipnonpubliclibraryclasses
-dontpreverify
-verbose
-optimizations !code/simplification/arithmetic,!field/*,!class/merging/*
-keep public class * extends android.app.Activity
-keep public class * extends android.app.Application
-keep public class * extends android.app.Service
-keep public class * extends android.content.BroadcastReceiver
-keep public class * extends android.content.ContentProvider
-keep public class * extends android.app.backup.BackupAgentHelper
-keep public class * extends android.preference.Preference
-keep public class com.android.vending.licensing.ILicensingService
-keepclasseswithmembernames class * {
native <methods>;
}
-keepclasseswithmembers class * {
public <init>(android.content.Context, android.util.AttributeSet);
}
-keepclasseswithmembers class * {
public <init>(android.content.Context, android.util.AttributeSet, int);
}
-keepclassmembers class * extends android.app.Activity {
public void *(android.view.View);
}
-keepclassmembers enum * {
public static **[] values();
public static ** valueOf(java.lang.String);
}
-keep class * implements android.os.Parcelable {
public static final android.os.Parcelable$Creator *;
}

View File

@ -0,0 +1,12 @@
# This file is automatically generated by Android Tools.
# Do not modify this file -- YOUR CHANGES WILL BE ERASED!
#
# This file must be checked in Version Control Systems.
#
# To customize properties used by the Ant build system use,
# "ant.properties", and override values to adapt the script to your
# project structure.
android.library=true
# Project target.
target=android-8

View File

@ -0,0 +1,13 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
>
<TextView
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:text="Hello World, ACTIVITY_ENTRY_NAME"
/>
</LinearLayout>

View File

@ -0,0 +1,4 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<string name="app_name">ACTIVITY_ENTRY_NAME</string>
</resources>

View File

@ -46,6 +46,13 @@ AC_DEFINE_UNQUOTED([LIB_VERSION_REVISION],
[[`echo "$LIB_VERSION" | sed -e 's/^[^:]*:\([^:]*\):.*$/\1/'`]],
[Library revision])
AM_CPPFLAGS="-I$srcdir/include"
AM_CFLAGS="-Wall -Wno-parentheses -Werror"
AM_CXXFLAGS="$AM_CFLAGS"
AC_SUBST([AM_CPPFLAGS])
AC_SUBST([AM_CFLAGS])
AC_SUBST([AM_CXXFLAGS])
dnl windows build
AC_CANONICAL_HOST
@ -73,13 +80,36 @@ documentation generation])
AC_ARG_VAR([XMLTOFLAGS], [additional arguments for xmlto])
AC_CHECK_PROGS([XMLTO], [xmlto], [:])
have_java="maybe"
AC_ARG_VAR([JAVA_HOME], [root location of JDK])
AS_IF([test "x$JAVA_HOME" = "x"],
[JAVA_PATH="$PATH"],
[JAVA_PATH="$JAVA_HOME/bin$PATH_SEPARATOR$PATH"])
AC_ARG_VAR([JAVAC], [location of Java language compiler])
AC_PATH_PROGS([JAVAC], [javac jikes ecj gcj], [:], [$JAVA_PATH])
AS_IF([test "x$JAVAC" = "x:"], [have_java="no"])
AC_ARG_VAR([JAVAH], [location of Java header generator])
AC_PATH_PROGS([JAVAH], [javah], [/bin/false], [$JAVA_PATH])
AC_ARG_VAR([JAR], [location of Java archive tool])
AC_PATH_PROGS([JAR], [jar], [:], [$JAVA_PATH])
AS_IF([test "x$JAR" = "x:"], [have_java="no"])
AC_ARG_VAR([JAVA], [location of Java application launcher])
AC_PATH_PROGS([JAVA], [java], [/bin/false], [$JAVA_PATH])
AC_ARG_VAR([CLASSPATH], [Java class path (include JUnit to run java tests)])
AS_IF([test "x$CLASSPATH" = "x"], [CLASSPATH="."])
dnl symbologies
AC_ARG_ENABLE([codes],
[AS_HELP_STRING([--enable-codes=SYMS],
[select symbologies to compile [default=ean,i25,code39,code128,qrcode]])],
[select symbologies to compile [default=ean,databar,code128,code93,code39,codabar,i25,qrcode]])],
[],
[enable_codes="ean,code39,code128,i25,qrcode"]) dnl pdf417
[enable_codes="ean,databar,code128,code93,code39,codabar,i25,qrcode"])
AC_DEFUN([ZBAR_CHK_CODE], [
AC_MSG_CHECKING([whether to build $2])
@ -97,11 +127,14 @@ AC_DEFUN([ZBAR_CHK_CODE], [
])dnl
ZBAR_CHK_CODE([ean], [EAN symbologies])
ZBAR_CHK_CODE([databar], [DataBar symbology])
ZBAR_CHK_CODE([code128], [Code 128 symbology])
ZBAR_CHK_CODE([code93], [Code 93 symbology])
ZBAR_CHK_CODE([code39], [Code 39 symbology])
ZBAR_CHK_CODE([pdf417], [PDF417 symbology])
ZBAR_CHK_CODE([codabar], [Codabar symbology])
ZBAR_CHK_CODE([i25], [Interleaved 2 of 5 symbology])
ZBAR_CHK_CODE([qrcode], [QR Code])
ZBAR_CHK_CODE([pdf417], [PDF417 symbology])
dnl libraries
@ -144,16 +177,26 @@ AC_ARG_ENABLE([video],
[],
[enable_video="yes"])
with_video="no"
AS_IF([test "x$enable_video" != "xno"],
[AS_IF([test "x$win32" = "xno"],
[AC_CHECK_LIB([v4l2], [v4l2_open], [],
[AC_MSG_WARN([v4l2 API not detected, upgrade your kernel!])])],
[AC_CHECK_HEADERS([vfw.h], [with_video="vfw"],
[AC_MSG_FAILURE([test for VfW video support failed!
configure --disable-video to skip building vidoe support.])])])
])
have_v4l1="no"
have_v4l2="no"
AS_IF([test "x$enable_video" = "xno"],
[],
[test "x$win32" = "xno"],
[AC_CHECK_HEADERS([linux/videodev.h], [have_v4l1="yes"])
AC_CHECK_HEADERS([linux/videodev2.h], [have_v4l2="yes"])
AS_IF([test "x$have_v4l2" = "xno" && test "x$have_v4l1" = "xno"],
[AC_MSG_FAILURE([test for video support failed!
rebuild your kernel to include video4linux support or
configure --disable-video to skip building video support.])],
[test "x$have_v4l2" = "xno"],
[AC_MSG_WARN([v4l2 API not detected, upgrade your kernel!])])],
[AC_CHECK_HEADERS([vfw.h], [with_video="vfw"],
[AC_MSG_FAILURE([test for VfW video support failed!
configure --disable-video to skip building video support.])])])
AM_CONDITIONAL([HAVE_VIDEO], [test "x$enable_video" != "xno"])
AM_CONDITIONAL([HAVE_V4L1], [test "x$have_v4l1" != "xno"])
AM_CONDITIONAL([HAVE_V4L2], [test "x$have_v4l2" != "xno"])
dnl X
AC_ARG_VAR([XSHM_LIBS], [linker flags for X shared memory extension])
@ -245,51 +288,105 @@ set appropriately or configure --without-jpeg])],
])
AM_CONDITIONAL([HAVE_JPEG], [test "x$with_jpeg" = "xyes"])
dnl ImageMagick
dnl ImageMagick or GraphicsMagick
dnl disable both if IM is explicitly disabled to preserve old behavior
AC_ARG_WITH([imagemagick],
[AS_HELP_STRING([--without-imagemagick],
[disable support for scanning images using ImageMagick])],
[disable support for scanning images with ImageMagick])],
[],
[with_imagemagick="yes"])
[with_imagemagick="check"])
AS_IF([test "x$with_imagemagick" != "xno"],
[PKG_CHECK_MODULES([MAGICK], [MagickWand >= 6.2.6], [],
[dnl Wand is deprecated in favor of MagickWand,
dnl but the latter doesn't exist in older verisons (bug #2848437)
AC_ARG_WITH([graphicsmagick],
[AS_HELP_STRING([--with-graphicsmagick],
[use GraphicsMagick alternative to ImageMagick])],
[],
[with_graphicsmagick="check"])
magick="UnknownMagick"
have_IM="maybe"
AS_IF([test "x$with_imagemagick" = "xno"], [],
[test "x$with_imagemagick" = "xyes" || \
test "x$with_graphicsmagick" != "xyes"],
[looked_for="ImageMagick >= 6.2.6"
PKG_CHECK_MODULES([MAGICK], [MagickWand >= 6.2.6],
[MAGICK_VERSION=`$PKG_CONFIG MagickWand --modversion`],
[dnl
dnl Wand is deprecated in favor of MagickWand,
dnl but the latter doesn't exist in older verisons (bug #2848437)
saved_error=$MAGICK_PKG_ERRORS
PKG_CHECK_MODULES([MAGICK], [Wand >= 6.2.6], [],
[AC_MSG_FAILURE([dnl
Unable to find ImageMagick >= 6.2.6:
PKG_CHECK_MODULES([MAGICK], [Wand >= 6.2.6],
[MAGICK_VERSION=`$PKG_CONFIG Wand --modversion`],
[have_IM="no"])])
AS_IF([test "x$have_IM" != "xno"],
[magick="ImageMagick"
AC_MSG_NOTICE([trying ImageMagick version $MAGICK_VERSION])
dnl double check ImageMagick install (bug #2582232)
CPPFLAGS_save="$CPPFLAGS"
CPPFLAGS="$CPPFLAGS $MAGICK_CFLAGS"
AC_CHECK_HEADER([wand/MagickWand.h],
[have_IM="yes"],
[have_IM="broken"])
CPPFLAGS="$CPPFLAGS_save"])])
have_GM="maybe"
AS_IF([test "x$have_IM" = "xyes"], [],
[test "x$with_graphicsmagick" = "xno"], [],
[test "x$with_graphicsmagick" = "xyes" || \
test "x$with_imagemagick" = "xcheck"],
[AS_IF([test "x$looked_for" = "x"],
[looked_for="GraphicsMagick"],
[looked_for="$looked_for or GraphicsMagick"])
PKG_CHECK_MODULES([MAGICK], [GraphicsMagickWand],
[have_GM="yes"
magick="GraphicsMagick"
MAGICK_VERSION=`$PKG_CONFIG GraphicsMagickWand --modversion`],
[have_GM="no"
AS_IF([test "x$saved_error" = "x"],
[saved_error=$MAGICK_PKG_ERRORS])])])
dnl now that we have collected all the info abt what Magick is available
dnl let the user know what we will or can't do
AS_IF([test "x$have_IM" = "xbroken" && test "x$have_GM" = "xyes"],
[AC_MSG_WARN([Your ImageMagick install is broken, using GraphicsMagick instead])])
AS_IF([test "x$have_IM" = "xyes" || test "x$have_GM" = "xyes"],
[AC_MSG_NOTICE([using $magick version $MAGICK_VERSION])],
[test "x$with_imagemagick" = "xno" && \
test "x$with_graphicsmagick" != "xyes"],
[AC_MSG_NOTICE([image scanning disabled -- zbarimg will *not* be built])],
[test "x$have_IM" = "xbroken"],
[AC_MSG_FAILURE([$magick package found but wand/MagickWand.h not installed?!
this is a problem with your $magick install, please try again after
resolving the inconsistency or installing GraphicsMagick alternative...])],
[AC_MSG_FAILURE([dnl
Unable to find $looked_for:
$saved_error
* Ensure that you installed any "development" packages for ImageMagick.
* Ensure that you installed any "development" packages for ImageMagick or
GraphicsMagick.
* Consider adjusting the PKG_CONFIG_PATH environment variable if you
installed software in a non-standard prefix.
* You may set the environment variables MAGICK_CFLAGS and MAGICK_LIBS
to avoid the need to call pkg-config.
See the pkg-config man page for more details.
* To avoid using ImageMagick altogether you may add the --without-imagemagick
flag to the configure command; the zbarimg program will not be built.
])])])
MAGICK_VERSION=`$PKG_CONFIG MagickWand --modversion`
AC_MSG_NOTICE([using ImageMagick version $MAGICK_VERSION])
* To avoid using ImageMagick or GraphicsMagick altogether you may add the
--without-imagemagick flag to the configure command; the zbarimg program
will *not* be built.
])])
dnl double check ImageMagick install (bug #2582232)
CPPFLAGS_save="$CPPFLAGS"
CPPFLAGS="$CPPFLAGS $MAGICK_CFLAGS"
AC_CHECK_HEADER([wand/MagickWand.h], [],
[AC_MSG_FAILURE([ImageMagick package found but wand/MagickWand.h not installed?!
this is a problem with your ImageMagick install,
please resolve the inconsistency and try again...])])
CPPFLAGS="$CPPFLAGS_save"])
AM_CONDITIONAL([HAVE_MAGICK], [test "x$with_imagemagick" = "xyes"])
AS_IF([test "x$have_IM" = "xyes"],
[AC_DEFINE([HAVE_IMAGEMAGICK], [1], [Define to 1 to use ImageMagick])],
[test "x$have_GM" = "xyes"],
[AC_DEFINE([HAVE_GRAPHICSMAGICK], [1], [Define to 1 to use GraphicsMagick])])
AM_CONDITIONAL([HAVE_MAGICK],
[test "x$have_IM" = "xyes" || test "x$have_GM" = "xyes"])
dnl Mozilla NPAPI
AC_ARG_WITH([npapi],
[AS_HELP_STRING([--with-npapi],
[enable support for Firefox/Mozilla/OpenOffice NPAPI plugin])],
[enable support for Firefox/Mozilla/OpenOffice plugin])],
[],
[with_npapi="no"])
@ -343,7 +440,16 @@ AS_IF([test "x$with_python" != "xno"],
[test -x "$PYTHON-config"],
[PYTHON_CFLAGS=`$PYTHON-config --cflags`],
[PYTHON_CFLAGS=`$PYTHON -c 'import distutils.sysconfig as s; print " ".join(s.get_config_vars("CFLAGS")) + " -I"+s.get_python_inc() + " -I"+s.get_python_inc(plat_specific=True)'`])
dnl FIXME now should check that #include <Python.h> compiles
dnl check that #include <Python.h> compiles (bug #3092663)
CPPFLAGS_save="$CPPFLAGS"
CPPFLAGS="$CPPFLAGS $PYTHON_CFLAGS"
AC_CHECK_HEADER([Python.h], [], [AC_MSG_ERROR([dnl
Python module enabled, but unable to compile Python.h.
Install the development package for python-$am_cv_python_version, or configure
--without-python to disable the python bindings.dnl
])])
CPPFLAGS="$CPPFLAGS_save"
AS_IF([test "x$with_gtk" = "xyes"],
[PKG_CHECK_MODULES([PYGTK], [pygtk-2.0])
@ -376,13 +482,39 @@ AS_IF([test "x$with_qt" != "xno"],
AM_CONDITIONAL([HAVE_QT], [test "x$with_qt" = "xyes"])
dnl Java
AC_ARG_WITH([java],
[AS_HELP_STRING([--without-java],
[disable support for Java interface])],
[],
[with_java="check"])
AC_ARG_VAR([JAVA_CFLAGS], [compiler flags for building JNI extensions])
AS_IF([test "x$JAVA_CFLAGS" = "x" && test "x$JAVA_HOME" != "x"],
[JAVA_CFLAGS="-I$JAVA_HOME/include"])
AS_IF([test "x$with_java" != "xno"],
[CPPFLAGS_save="$CPPFLAGS"
CPPFLAGS="$CPPFLAGS $JAVA_CFLAGS"
AC_CHECK_HEADER([jni.h], [], [have_java="no"])
CPPFLAGS="$CPPFLAGS_save"
AS_IF([test "x$have_java" != "xno"],
[with_java="yes"],
[test "x$with_java" = "xyes"],
[AC_MSG_FAILURE([unable to find Java JNI! ensure CFLAGS are set
appropriately or configure --without-java])],
[with_java="no"])
])
AM_CONDITIONAL([HAVE_JAVA], [test "x$with_java" = "xyes"])
dnl header files
dnl FIXME switches for shm, mmap
AC_HEADER_ASSERT
AC_CHECK_HEADERS([fcntl.h features.h inttypes.h stdlib.h string.h unistd.h \
sys/ioctl.h sys/time.h sys/times.h sys/ipc.h sys/shm.h sys/mman.h])
AC_CHECK_HEADERS([errno.h fcntl.h features.h inttypes.h stdlib.h string.h \
unistd.h sys/types.h sys/stat.h sys/ioctl.h sys/time.h sys/times.h \
sys/ipc.h sys/shm.h sys/mman.h])
dnl types
@ -421,6 +553,7 @@ AC_CONFIG_COMMANDS([doc/reldate.xml],
AC_CONFIG_FILES([
Makefile
java/Makefile
zbar.pc
zbar-gtk.pc
zbar-qt.pc
@ -435,14 +568,16 @@ echo "please verify that the detected configuration matches your expectations:"
echo "------------------------------------------------------------------------"
echo "X --with-x=$have_x"
echo "pthreads --enable-pthread=$enable_pthread"
echo "v4l2 --enable-video=$enable_video"
echo "v4l --enable-video=$enable_video"
AS_IF([test "x$enable_video" != "xyes"],
[echo " => zbarcam video scanner will *NOT* be built"])
echo "jpeg --with-jpeg=$with_jpeg"
AS_IF([test "x$with_jpeg" != "xyes"],
[echo " => JPEG image conversions will *NOT* be supported"])
echo "Magick++ --with-imagemagick=$with_imagemagick"
AS_IF([test "x$with_imagemagick" != "xyes"],
AS_IF([test "x$have_GM" = "xyes"],
[echo "GraphicsMagick --with-graphicsmagick=yes"],
[echo "ImageMagick --with-imagemagick=$with_imagemagick"])
AS_IF([test "x$have_IM" != "xyes" && test "x$have_GM" != "xyes"],
[echo " => the zbarimg file scanner will *NOT* be built"])
echo "Python --with-python=$with_python"
echo "GTK+ --with-gtk=$with_gtk"
@ -453,6 +588,9 @@ AS_IF([test "x$with_gtk" != "xyes"],
echo "Qt4 --with-qt=$with_qt"
AS_IF([test "x$with_qt" != "xyes"],
[echo " => the Qt4 widget will *NOT* be built"])
echo "Java --with-java=$with_java"
AS_IF([test "x$with_java" != "xyes"],
[echo " => the Java interface will *NOT* be built"])
#echo "NPAPI Plugin --with-npapi=$with_npapi"
#AS_IF([test "x$with_mozilla" != "xyes"],
# [echo " => the Mozilla/Firefox/OpenOffice plugin will *NOT* be built"])

View File

@ -2,6 +2,7 @@
DOCSOURCES = doc/manual.xml doc/version.xml doc/reldate.xml \
doc/ref/zbarimg.xml doc/ref/zbarcam.xml doc/ref/commonoptions.xml
MAINTAINERCLEANFILES += doc/man/man.stamp doc/version.xml doc/reldate.xml
# man page targets to distribute and install
dist_man_MANS =

View File

@ -9,9 +9,12 @@
<address><a href="mailto:spadix@users.sourceforge.net">spadix@users.sourceforge.net</a></address>
<p>Copyright 2008-2009 (c) Jeff Brown - All Rights Reserved.</p>
<p>Verbatim copying and distribution of this entire article are
permitted worldwide, without royalty, in any medium, provided this
notice, and the copyright notice, are preserved.</p>
<p>Copyright 2008-2010 (c) Jeff Brown</p>
<p>This documentation is part of the ZBar Barcode Reader; you can
redistribute it and/or modify it under the terms of the
<a href="http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html">GNU
Lesser General Public License</a> as published by the Free Software
Foundation; either version 2.1 of the License, or (at your option) any
later version.</p>
</body></html>

View File

@ -29,10 +29,10 @@
<year>2007</year>
<year>2008</year>
<year>2009</year>
<year>2010</year>
<holder>Jeff Brown</holder>
</copyright>
<legalnotice><para>All Rights Reserved</para></legalnotice>
<!-- <legalnotice><para>insert GNU FDL header?</para></legalnotice> -->
</bookinfo>
<chapter id="intro">
@ -47,7 +47,4 @@
&refzbarimg;
</reference>
<!-- insert GNU FDL? -->
</book>

View File

@ -47,8 +47,9 @@
<option>ean13</option>, <option>ean8</option>,
<option>upca</option>, <option>upce</option>,
<option>isbn13</option>, <option>isbn10</option>,
<option>i25</option>, <option>code39</option>,
<option>code128</option> or the special value <option>*</option>.
<option>i25</option>, <option>codabar</option>, <option>code39</option>,
<option>code93</option>, <option>code128</option>,
<option>qrcode</option> or the special value <option>*</option>.
If <replaceable class="parameter">symbology</replaceable> is
omitted or <option>*</option>, the <replaceable
class="parameter">config</replaceable> will be set for all
@ -128,11 +129,12 @@
If a decode result is outside the configured min/max range
(inclusive), it will not be reported. Set to 0 to disable the
corresponding check. This setting applies to variable-length
symbologies: <option>i25</option>, <option>code39</option>,
<option>code128</option> and <option>pdf417</option>.
<option>min-length</option> defaults to 6 for <option>i25</option>
and 1 for <option>code39</option> (per Code 39 autodiscrimination
recommendation); all others default to 0</simpara>
symbologies: <option>i25</option>, <option>codabar</option>,
<option>code39</option>, <option>code128</option> and
<option>pdf417</option>. <option>min-length</option> defaults to 6
for <option>i25</option> and 1 for <option>code39</option> (per Code
39 autodiscrimination recommendation); all others default to
0</simpara>
</listitem>
</varlistentry>

View File

@ -60,9 +60,10 @@
<filename>/dev/video0</filename></para>
<para>The underlying library currently supports EAN-13 (including
UPC and ISBN subsets), EAN-8, Code 128, Code 39, and Interleaved
2 of 5 symbologies. The specific type of each detected symbol is
printed with the decoded data.</para>
UPC and ISBN subsets), EAN-8, DataBar, DataBar Expanded, Code 128,
Code 93, Code 39, Codabar, Interleaved 2 of 5 and QR Code symbologies.
The specific type of each detected symbol is printed with the decoded
data.</para>
</refsection>
@ -159,6 +160,37 @@
</para>
</refsection>
<refsection>
<title>Exit Status</title>
<para><command>zbarcam</command> returns an exit code to indicate the
status of the program execution. Current exit codes are:</para>
<variablelist>
<varlistentry>
<term>0</term>
<listitem>
<para>Successful program completion.</para>
</listitem>
</varlistentry>
<varlistentry>
<term>1</term>
<listitem>
<para>An error occurred. This includes bad arguments and I/O
errors.</para>
</listitem>
</varlistentry>
<varlistentry>
<term>2</term>
<listitem>
<para>A fatal error occurred.</para>
</listitem>
</varlistentry>
</variablelist>
</refsection>
<refsection>
<title>See Also</title>
<para><xref linkend="zbarimg"/></para>

View File

@ -59,9 +59,10 @@
displayed to the screen.</para>
<para>The underlying library currently supports EAN-13 (including
UPC and ISBN subsets), EAN-8, Code 128, Code 39, and Interleaved
2 of 5 symbologies. The specific type of each detected symbol is
printed with the decoded data.</para>
UPC and ISBN subsets), EAN-8, DataBar, DataBar Expanded, Code 128,
Code 93, Code 39, Codabar, Interleaved 2 of 5 and QR Code symbologies.
The specific type of each detected symbol is printed with the decoded
data.</para>
<para>Note that "<filename><replaceable>image</replaceable></filename>"
@ -165,6 +166,56 @@
</para>
</refsection>
<refsection>
<title>Exit Status</title>
<para><command>zbarimg</command> returns an exit code to indicate the
status of the program execution. Current exit codes are:</para>
<variablelist>
<varlistentry>
<term>0</term>
<listitem>
<para>Barcodes successfully detected in all images. Warnings may
have been generated, but no errors.</para>
</listitem>
</varlistentry>
<varlistentry>
<term>1</term>
<listitem>
<para>An error occurred while processing some image(s). This
includes bad arguments, I/O errors and image handling errors from
ImageMagick.</para>
</listitem>
</varlistentry>
<varlistentry>
<term>2</term>
<listitem>
<para>ImageMagick fatal error.</para>
</listitem>
</varlistentry>
<varlistentry>
<term>3</term>
<listitem>
<para>The user quit the program before all images were scanned.
Only applies when running in interactive mode
(with <option>--display</option>)</para>
</listitem>
</varlistentry>
<varlistentry>
<term>4</term>
<listitem>
<para>No barcode was detected in one or more of the images. No
other errors occurred.</para>
</listitem>
</varlistentry>
</variablelist>
</refsection>
<refsection>
<title>See Also</title>
<para><xref linkend="zbarcam"/></para>

View File

@ -1,71 +0,0 @@
#!/usr/bin/perl
#------------------------------------------------------------------------
# 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
#------------------------------------------------------------------------
use warnings;
use strict;
use Barcode::ZBar;
use Image::Magick;
warn("no input files specified?\n") if(!@ARGV);
# running output document
my $out = undef;
# barcode scanner
my $scanner = Barcode::ZBar::ImageScanner->new();
foreach my $file (@ARGV) {
print "scanning from \"$file\"\n";
my $imseq = Image::Magick->new();
my $err = $imseq->Read($file);
warn($err) if($err);
foreach my $page (@$imseq) {
# convert ImageMagick page to ZBar image
my $zimg = Barcode::ZBar::Image->new();
$zimg->set_format('Y800');
$zimg->set_size($page->Get(qw(columns rows)));
$zimg->set_data($page->Clone()->ImageToBlob(magick => 'GRAY', depth => 8));
# scan for barcodes
if($scanner->scan_image($zimg)) {
# write out previous document
$out->write() if($out);
# use first symbol found to name next image (FIXME sanitize)
my $data = ($zimg->get_symbols())[0]->get_data();
my $idx = $page->Get('scene') + 1;
print "splitting $data from page $idx\n";
# create new output document
$out = Image::Magick->new(filename => $data);
}
# append this page to current output
push(@$out, $page) if($out);
}
# write out final document
$out->write() if($out);
}

47
examples/processor.c Normal file
View File

@ -0,0 +1,47 @@
#include <stdio.h>
#include <zbar.h>
static void my_handler (zbar_image_t *image,
const void *userdata)
{
/* extract results */
const zbar_symbol_t *symbol = zbar_image_first_symbol(image);
for(; symbol; symbol = zbar_symbol_next(symbol)) {
/* do something useful with results */
zbar_symbol_type_t typ = zbar_symbol_get_type(symbol);
const char *data = zbar_symbol_get_data(symbol);
printf("decoded %s symbol \"%s\"\n",
zbar_get_symbol_name(typ), data);
}
}
int main (int argc, char **argv)
{
const char *device = "/dev/video0";
/* create a Processor */
zbar_processor_t *proc = zbar_processor_create(1);
/* configure the Processor */
zbar_processor_set_config(proc, 0, ZBAR_CFG_ENABLE, 1);
/* initialize the Processor */
if(argc > 1)
device = argv[1];
zbar_processor_init(proc, device, 1);
/* setup a callback */
zbar_processor_set_data_handler(proc, my_handler, NULL);
/* enable the preview window */
zbar_processor_set_visible(proc, 1);
zbar_processor_set_active(proc, 1);
/* keep scanning until user provides key/mouse input */
zbar_processor_user_wait(proc, -1);
/* clean up */
zbar_processor_destroy(proc);
return(0);
}

45
examples/processor.cpp Normal file
View File

@ -0,0 +1,45 @@
#include <iostream>
#include <zbar.h>
using namespace std;
using namespace zbar;
class MyHandler : public Image::Handler
{
void image_callback (Image &image)
{
for(SymbolIterator symbol = image.symbol_begin();
symbol != image.symbol_end();
++symbol)
cout << "decoded " << symbol->get_type_name() << " symbol "
<< "\"" << symbol->get_data() << "\"" << endl;
}
};
int main (int argc, char **argv)
{
// create and initialize a Processor
const char *device = "/dev/video0";
if(argc > 1)
device = argv[1];
Processor proc(true, device);
// configure the Processor
proc.set_config(ZBAR_NONE, ZBAR_CFG_ENABLE, 1);
// setup a callback
MyHandler my_handler;
proc.set_handler(my_handler);
// enable the preview window
proc.set_visible();
proc.set_active();
try {
// keep scanning until user provides key/mouse input
proc.user_wait();
}
catch(ClosedError &e) {
}
return(0);
}

View File

@ -1,35 +0,0 @@
#!/usr/bin/env perl
use warnings;
use strict;
require Barcode::ZBar;
# create a Processor
my $proc = Barcode::ZBar::Processor->new();
# configure the Processor
$proc->parse_config("enable");
# initialize the Processor
$proc->init($ARGV[0] || '/dev/video0');
# setup a callback
sub my_handler {
my ($proc, $image, $closure) = @_;
# extract results
foreach my $symbol ($proc->get_results()) {
# do something useful with results
print('decoded ' . $symbol->get_type() .
' symbol "' . $symbol->get_data() . "\"\n");
}
}
$proc->set_data_handler(\&my_handler);
# enable the preview window
$proc->set_visible();
# initiate scanning
$proc->set_active();
# keep scanning until user provides key/mouse input
$proc->user_wait();

View File

@ -1,29 +0,0 @@
#!/usr/bin/env perl
use warnings;
use strict;
require Barcode::ZBar;
# create a Processor
my $proc = Barcode::ZBar::Processor->new();
# configure the Processor
$proc->parse_config("enable");
# initialize the Processor
$proc->init($ARGV[0] || '/dev/video0');
# enable the preview window
$proc->set_visible();
# read at least one barcode (or until window closed)
$proc->process_one();
# hide the preview window
$proc->set_visible(0);
# extract results
foreach my $symbol ($proc->get_results()) {
# do something useful with results
print('decoded ' . $symbol->get_type() .
' symbol "' . $symbol->get_data() . "\"\n");
}

View File

@ -3,6 +3,20 @@
#include <png.h>
#include <zbar.h>
#if !defined(PNG_LIBPNG_VER) || \
PNG_LIBPNG_VER < 10018 || \
(PNG_LIBPNG_VER > 10200 && \
PNG_LIBPNG_VER < 10209)
/* Changes to Libpng from version 1.2.42 to 1.4.0 (January 4, 2010)
* ...
* 2. m. The function png_set_gray_1_2_4_to_8() was removed. It has been
* deprecated since libpng-1.0.18 and 1.2.9, when it was replaced with
* png_set_expand_gray_1_2_4_to_8() because the former function also
* expanded palette images.
*/
# define png_set_expand_gray_1_2_4_to_8 png_set_gray_1_2_4_to_8
#endif
zbar_image_scanner_t *scanner = NULL;
/* to complete a runnable example, this abbreviated implementation of
@ -30,7 +44,7 @@ static void get_data (const char *name,
if(color & PNG_COLOR_TYPE_PALETTE)
png_set_palette_to_rgb(png);
if(color == PNG_COLOR_TYPE_GRAY && bits < 8)
png_set_gray_1_2_4_to_8(png);
png_set_expand_gray_1_2_4_to_8(png);
if(bits == 16)
png_set_strip_16(png);
if(color & PNG_COLOR_MASK_ALPHA)
@ -65,7 +79,7 @@ int main (int argc, char **argv)
/* wrap image data */
zbar_image_t *image = zbar_image_create();
zbar_image_set_format(image, *(int*)"Y800");
zbar_image_set_format(image, zbar_fourcc('Y','8','0','0'));
zbar_image_set_size(image, width, height);
zbar_image_set_data(image, raw, width * height, zbar_image_free_data);

View File

@ -1,37 +0,0 @@
#!/usr/bin/perl
use warnings;
use strict;
require Image::Magick;
require Barcode::ZBar;
$ARGV[0] || die;
# create a reader
my $scanner = Barcode::ZBar::ImageScanner->new();
# configure the reader
$scanner->parse_config("enable");
# obtain image data
my $magick = Image::Magick->new();
$magick->Read($ARGV[0]) && die;
my $raw = $magick->ImageToBlob(magick => 'GRAY', depth => 8);
# wrap image data
my $image = Barcode::ZBar::Image->new();
$image->set_format('Y800');
$image->set_size($magick->Get(qw(columns rows)));
$image->set_data($raw);
# scan the image for barcodes
my $n = $scanner->scan_image($image);
# extract results
foreach my $symbol ($image->get_symbols()) {
# do something useful with results
print('decoded ' . $symbol->get_type() .
' symbol "' . $symbol->get_data() . "\"\n");
}
# clean up
undef($image);

View File

@ -3,7 +3,7 @@ use warnings;
use strict;
use Frontier::Client;
use Data::Dumper;
my $s = Frontier::Client->new('url' => 'http://dev.upcdatabase.com/rpc');
my $s = Frontier::Client->new('url' => 'http://www.upcdatabase.com/rpc');
$| = 1; # autoflush

View File

@ -2,7 +2,7 @@
from xmlrpclib import ServerProxy
import sys, re
server = ServerProxy("http://dev.upcdatabase.com/rpc")
server = ServerProxy("http://www.upcdatabase.com/rpc")
ean_re = re.compile(r'^(UPC-A:|EAN-13:)?(\d{11,13})$', re.M)
def lookup(decode):

View File

@ -1,5 +1,5 @@
/*------------------------------------------------------------------------
* Copyright 2008-2009 (c) Jeff Brown <spadix@users.sourceforge.net>
* Copyright 2008-2010 (c) Jeff Brown <spadix@users.sourceforge.net>
*
* This file is part of the ZBar Bar Code Reader.
*
@ -35,11 +35,6 @@
#define DEFAULT_WIDTH 640
#define DEFAULT_HEIGHT 480
/* adapted from v4l2 spec */
#define fourcc(a, b, c, d) \
((long)(a) | ((long)(b) << 8) | \
((long)(c) << 16) | ((long)(d) << 24))
enum {
DECODED,
DECODED_TEXT,
@ -88,15 +83,15 @@ gboolean zbar_gtk_image_from_pixbuf (zbar_image_t *zimg,
/* these are all guesses... */
if(nchannels == 3 && bps == 8)
type = fourcc('R','G','B','3');
type = zbar_fourcc('R','G','B','3');
else if(nchannels == 4 && bps == 8)
type = fourcc('B','G','R','4'); /* FIXME alpha flipped?! */
type = zbar_fourcc('B','G','R','4'); /* FIXME alpha flipped?! */
else if(nchannels == 1 && bps == 8)
type = fourcc('Y','8','0','0');
type = zbar_fourcc('Y','8','0','0');
else if(nchannels == 3 && bps == 5)
type = fourcc('R','G','B','R');
type = zbar_fourcc('R','G','B','R');
else if(nchannels == 3 && bps == 4)
type = fourcc('R','4','4','4'); /* FIXME maybe? */
type = zbar_fourcc('R','4','4','4'); /* FIXME maybe? */
else {
g_warning("unsupported combination: nchannels=%d bps=%d\n",
nchannels, bps);
@ -142,10 +137,6 @@ static inline gboolean zbar_gtk_video_open (ZBarGtk *self,
gdk_threads_enter();
zbar->req_width = DEFAULT_WIDTH;
zbar->req_height = DEFAULT_HEIGHT;
gtk_widget_queue_resize(GTK_WIDGET(self));
zbar->video_opened = FALSE;
if(zbar->thread)
g_object_notify(G_OBJECT(self), "video-opened");
@ -184,6 +175,10 @@ static inline gboolean zbar_gtk_video_open (ZBarGtk *self,
*/
gdk_threads_enter();
if(zbar->video_width && zbar->video_height)
zbar_video_request_size(zbar->video,
zbar->video_width, zbar->video_height);
video_opened = !zbar_negotiate_format(zbar->video, zbar->window);
if(video_opened) {
@ -209,7 +204,7 @@ static inline int zbar_gtk_process_image (ZBarGtk *self,
if(!image)
return(-1);
zbar_image_t *tmp = zbar_image_convert(image, fourcc('Y','8','0','0'));
zbar_image_t *tmp = zbar_image_convert(image, zbar_fourcc('Y','8','0','0'));
if(!tmp)
return(-1);
@ -236,7 +231,6 @@ static inline int zbar_gtk_process_image (ZBarGtk *self,
/* FIXME skip this when unconnected? */
gchar *text = g_strconcat(zbar_get_symbol_name(type),
zbar_get_addon_name(type),
":",
data,
NULL);
@ -560,6 +554,19 @@ gboolean zbar_gtk_get_video_opened (ZBarGtk *self)
return(zbar->video_opened);
}
void zbar_gtk_request_video_size (ZBarGtk *self,
int width,
int height)
{
if(!self->_private || width < 0 || height < 0)
return;
ZBarGtkPrivate *zbar = ZBAR_GTK_PRIVATE(self->_private);
zbar->req_width = zbar->video_width = width;
zbar->req_height = zbar->video_height = height;
gtk_widget_queue_resize(GTK_WIDGET(self));
}
static void zbar_gtk_set_property (GObject *object,
guint prop_id,
const GValue *value,
@ -613,8 +620,8 @@ static void zbar_gtk_init (ZBarGtk *self)
zbar->window = zbar_window_create();
g_assert(zbar->window);
zbar->req_width = DEFAULT_WIDTH;
zbar->req_height = DEFAULT_HEIGHT;
zbar->req_width = zbar->video_width = DEFAULT_WIDTH;
zbar->req_height = zbar->video_width = DEFAULT_HEIGHT;
/* spawn a thread to handle decoding and video */
zbar->queue = g_async_queue_new();

View File

@ -71,6 +71,7 @@ typedef struct _ZBarGtkPrivate
* protected by main gui lock
*/
unsigned req_width, req_height;
unsigned video_width, video_height;
gboolean video_opened;
/* window is shared: owned by main gui thread.

View File

@ -1,5 +1,5 @@
/*------------------------------------------------------------------------
* Copyright 2007-2009 (c) Jeff Brown <spadix@users.sourceforge.net>
* Copyright 2007-2010 (c) Jeff Brown <spadix@users.sourceforge.net>
*
* This file is part of the ZBar Bar Code Reader.
*
@ -86,23 +86,58 @@ typedef enum zbar_color_e {
typedef enum zbar_symbol_type_e {
ZBAR_NONE = 0, /**< no symbol decoded */
ZBAR_PARTIAL = 1, /**< intermediate status */
ZBAR_EAN2 = 2, /**< GS1 2-digit add-on */
ZBAR_EAN5 = 5, /**< GS1 5-digit add-on */
ZBAR_EAN8 = 8, /**< EAN-8 */
ZBAR_UPCE = 9, /**< UPC-E */
ZBAR_ISBN10 = 10, /**< ISBN-10 (from EAN-13). @since 0.4 */
ZBAR_UPCA = 12, /**< UPC-A */
ZBAR_EAN13 = 13, /**< EAN-13 */
ZBAR_ISBN13 = 14, /**< ISBN-13 (from EAN-13). @since 0.4 */
ZBAR_COMPOSITE = 15, /**< EAN/UPC composite */
ZBAR_I25 = 25, /**< Interleaved 2 of 5. @since 0.4 */
ZBAR_DATABAR = 34, /**< GS1 DataBar (RSS). @since 0.11 */
ZBAR_DATABAR_EXP = 35, /**< GS1 DataBar Expanded. @since 0.11 */
ZBAR_CODABAR = 38, /**< Codabar. @since 0.11 */
ZBAR_CODE39 = 39, /**< Code 39. @since 0.4 */
ZBAR_PDF417 = 57, /**< PDF417. @since 0.6 */
ZBAR_QRCODE = 64, /**< QR Code. @since 0.10 */
ZBAR_CODE93 = 93, /**< Code 93. @since 0.11 */
ZBAR_CODE128 = 128, /**< Code 128 */
ZBAR_SYMBOL = 0x00ff, /**< mask for base symbol type */
ZBAR_ADDON2 = 0x0200, /**< 2-digit add-on flag */
ZBAR_ADDON5 = 0x0500, /**< 5-digit add-on flag */
ZBAR_ADDON = 0x0700, /**< add-on flag mask */
/** mask for base symbol type.
* @deprecated in 0.11, remove this from existing code
*/
ZBAR_SYMBOL = 0x00ff,
/** 2-digit add-on flag.
* @deprecated in 0.11, a ::ZBAR_EAN2 component is used for
* 2-digit GS1 add-ons
*/
ZBAR_ADDON2 = 0x0200,
/** 5-digit add-on flag.
* @deprecated in 0.11, a ::ZBAR_EAN5 component is used for
* 5-digit GS1 add-ons
*/
ZBAR_ADDON5 = 0x0500,
/** add-on flag mask.
* @deprecated in 0.11, GS1 add-ons are represented using composite
* symbols of type ::ZBAR_COMPOSITE; add-on components use ::ZBAR_EAN2
* or ::ZBAR_EAN5
*/
ZBAR_ADDON = 0x0700,
} zbar_symbol_type_t;
/** decoded symbol coarse orientation.
* @since 0.11
*/
typedef enum zbar_orientation_e {
ZBAR_ORIENT_UNKNOWN = -1, /**< unable to determine orientation */
ZBAR_ORIENT_UP, /**< upright, read left to right */
ZBAR_ORIENT_RIGHT, /**< sideways, read top to bottom */
ZBAR_ORIENT_DOWN, /**< upside-down, read right to left */
ZBAR_ORIENT_LEFT, /**< sideways, read bottom to top */
} zbar_orientation_t;
/** error codes. */
typedef enum zbar_error_e {
ZBAR_OK = 0, /**< no error */
@ -133,12 +168,33 @@ typedef enum zbar_config_e {
ZBAR_CFG_MIN_LEN = 0x20, /**< minimum data length for valid decode */
ZBAR_CFG_MAX_LEN, /**< maximum data length for valid decode */
ZBAR_CFG_UNCERTAINTY = 0x40,/**< required video consistency frames */
ZBAR_CFG_POSITION = 0x80, /**< enable scanner to collect position data */
ZBAR_CFG_X_DENSITY = 0x100, /**< image scanner vertical scan density */
ZBAR_CFG_Y_DENSITY, /**< image scanner horizontal scan density */
} zbar_config_t;
/** decoder symbology modifier flags.
* @since 0.11
*/
typedef enum zbar_modifier_e {
/** barcode tagged as GS1 (EAN.UCC) reserved
* (eg, FNC1 before first data character).
* data may be parsed as a sequence of GS1 AIs
*/
ZBAR_MOD_GS1 = 0,
/** barcode tagged as AIM reserved
* (eg, FNC1 after first character or digit pair)
*/
ZBAR_MOD_AIM,
/** number of modifiers */
ZBAR_MOD_NUM,
} zbar_modifier_t;
/** retrieve runtime library version information.
* @param major set to the running major version (unless NULL)
* @param minor set to the running minor version (unless NULL)
@ -168,9 +224,32 @@ extern const char *zbar_get_symbol_name(zbar_symbol_type_t sym);
* @param sym symbol type encoding
* @returns static string name for any addon, or the empty string
* if no addons were decoded
* @deprecated in 0.11
*/
extern const char *zbar_get_addon_name(zbar_symbol_type_t sym);
/** retrieve string name for configuration setting.
* @param config setting to name
* @returns static string name for config,
* or the empty string if value is not a known config
*/
extern const char *zbar_get_config_name(zbar_config_t config);
/** retrieve string name for modifier.
* @param modifier flag to name
* @returns static string name for modifier,
* or the empty string if the value is not a known flag
*/
extern const char *zbar_get_modifier_name(zbar_modifier_t modifier);
/** retrieve string name for orientation.
* @param orientation orientation encoding
* @returns the static string name for the specified orientation,
* or "UNKNOWN" if the orientation is not recognized
* @since 0.11
*/
extern const char *zbar_get_orientation_name(zbar_orientation_t orientation);
/** parse a configuration string of the form "[symbology.]config[=value]".
* the config must match one of the recognized names.
* the symbology, if present, must match one of the recognized names.
@ -184,6 +263,30 @@ extern int zbar_parse_config(const char *config_string,
zbar_config_t *config,
int *value);
/** consistently compute fourcc values across architectures
* (adapted from v4l2 specification)
* @since 0.11
*/
#define zbar_fourcc(a, b, c, d) \
((unsigned long)(a) | \
((unsigned long)(b) << 8) | \
((unsigned long)(c) << 16) | \
((unsigned long)(d) << 24))
/** parse a fourcc string into its encoded integer value.
* @since 0.11
*/
static inline unsigned long zbar_fourcc_parse (const char *format)
{
unsigned long fourcc = 0;
if(format) {
int i;
for(i = 0; i < 4 && format[i]; i++)
fourcc |= ((unsigned long)format[i]) << (i * 8);
}
return(fourcc);
}
/** @internal type unsafe error API (don't use) */
extern int _zbar_error_spew(const void *object,
int verbosity);
@ -229,6 +332,20 @@ extern void zbar_symbol_ref(const zbar_symbol_t *symbol,
*/
extern zbar_symbol_type_t zbar_symbol_get_type(const zbar_symbol_t *symbol);
/** retrieve symbology boolean config settings.
* @returns a bitmask indicating which configs were set for the detected
* symbology during decoding.
* @since 0.11
*/
extern unsigned int zbar_symbol_get_configs(const zbar_symbol_t *symbol);
/** retrieve symbology modifier flag settings.
* @returns a bitmask indicating which characteristics were detected
* during decoding.
* @since 0.11
*/
extern unsigned int zbar_symbol_get_modifiers(const zbar_symbol_t *symbol);
/** retrieve data decoded from symbol.
* @returns the data string
*/
@ -284,6 +401,14 @@ extern int zbar_symbol_get_loc_x(const zbar_symbol_t *symbol,
extern int zbar_symbol_get_loc_y(const zbar_symbol_t *symbol,
unsigned index);
/** retrieve general orientation of decoded symbol.
* @returns a coarse, axis-aligned indication of symbol orientation or
* ::ZBAR_ORIENT_UNKNOWN if unknown
* @since 0.11
*/
extern zbar_orientation_t
zbar_symbol_get_orientation(const zbar_symbol_t *symbol);
/** iterate the set to which this symbol belongs (there can be only one).
* @returns the next symbol in the set, or
* @returns NULL when no more results are available
@ -357,6 +482,14 @@ extern int zbar_symbol_set_get_size(const zbar_symbol_set_t *symbols);
extern const zbar_symbol_t*
zbar_symbol_set_first_symbol(const zbar_symbol_set_t *symbols);
/** raw result iterator.
* @returns the first decoded symbol result in a set, *before* filtering
* @returns NULL if the set is empty
* @since 0.11
*/
extern const zbar_symbol_t*
zbar_symbol_set_first_unfiltered(const zbar_symbol_set_t *symbols);
/*@}*/
/*------------------------------------------------------------*/
@ -456,6 +589,25 @@ extern unsigned zbar_image_get_width(const zbar_image_t *image);
*/
extern unsigned zbar_image_get_height(const zbar_image_t *image);
/** retrieve both dimensions of the image.
* fills in the width and height in samples
*/
extern void zbar_image_get_size(const zbar_image_t *image,
unsigned *width,
unsigned *height);
/** retrieve the crop rectangle.
* fills in the image coordinates of the upper left corner and size
* of an axis-aligned rectangular area of the image that will be scanned.
* defaults to the full image
* @since 0.11
*/
extern void zbar_image_get_crop(const zbar_image_t *image,
unsigned *x,
unsigned *y,
unsigned *width,
unsigned *height);
/** return the image sample data. the returned data buffer is only
* valid until zbar_image_destroy() is called
*/
@ -505,12 +657,24 @@ extern void zbar_image_set_sequence(zbar_image_t *image,
unsigned sequence_num);
/** specify the pixel size of the image.
* @note this also resets the crop rectangle to the full image
* (0, 0, width, height)
* @note this does not affect the data!
*/
extern void zbar_image_set_size(zbar_image_t *image,
unsigned width,
unsigned height);
/** specify a rectangular region of the image to scan.
* the rectangle will be clipped to the image boundaries.
* defaults to the full image specified by zbar_image_set_size()
*/
extern void zbar_image_set_crop(zbar_image_t *image,
unsigned x,
unsigned y,
unsigned width,
unsigned height);
/** specify image sample data. when image data is no longer needed by
* the library the specific data cleanup handler will be called
* (unless NULL)
@ -1148,6 +1312,14 @@ static inline int zbar_decoder_parse_config (zbar_decoder_t *decoder,
zbar_decoder_set_config(decoder, sym, cfg, val));
}
/** retrieve symbology boolean config settings.
* @returns a bitmask indicating which configs are currently set for the
* specified symbology.
* @since 0.11
*/
extern unsigned int zbar_decoder_get_configs(const zbar_decoder_t *decoder,
zbar_symbol_type_t symbology);
/** clear all decoder state.
* any partial symbols are flushed
*/
@ -1195,6 +1367,20 @@ zbar_decoder_get_data_length(const zbar_decoder_t *decoder);
extern zbar_symbol_type_t
zbar_decoder_get_type(const zbar_decoder_t *decoder);
/** retrieve modifier flags for the last decoded symbol.
* @returns a bitmask indicating which characteristics were detected
* during decoding.
* @since 0.11
*/
extern unsigned int zbar_decoder_get_modifiers(const zbar_decoder_t *decoder);
/** retrieve last decode direction.
* @returns 1 for forward and -1 for reverse
* @returns 0 if the decode direction is unknown or does not apply
* @since 0.11
*/
extern int zbar_decoder_get_direction(const zbar_decoder_t *decoder);
/** setup data handler callback.
* the registered function will be called by the decoder
* just before zbar_decode_width() returns a non-zero value.

View File

@ -1,5 +1,5 @@
//------------------------------------------------------------------------
// Copyright 2007-2009 (c) Jeff Brown <spadix@users.sourceforge.net>
// Copyright 2007-2010 (c) Jeff Brown <spadix@users.sourceforge.net>
//
// This file is part of the ZBar Bar Code Reader.
//
@ -115,6 +115,7 @@ class Decoder {
/// retrieve string name for last decode addon.
/// see zbar_get_addon_name()
/// @deprecated in 0.11
const char *get_addon_name () const
{
return(zbar_get_addon_name(zbar_decoder_get_type(_decoder)));
@ -149,6 +150,14 @@ class Decoder {
return(zbar_decoder_get_data_length(_decoder));
}
/// retrieve last decode direction.
/// see zbar_decoder_get_direction()
/// @since 0.11
int get_direction() const
{
return(zbar_decoder_get_direction(_decoder));
}
/// setup callback to handle result data.
void set_handler (Handler &handler)
{

View File

@ -1,5 +1,5 @@
//------------------------------------------------------------------------
// Copyright 2007-2009 (c) Jeff Brown <spadix@users.sourceforge.net>
// Copyright 2007-2010 (c) Jeff Brown <spadix@users.sourceforge.net>
//
// This file is part of the ZBar Bar Code Reader.
//
@ -67,7 +67,12 @@ public:
{
if(userdata) {
Image *image = (Image*)zbar_image_get_userdata(zimg);
((Handler*)userdata)->image_callback(*image);
if(image)
((Handler*)userdata)->image_callback(*image);
else {
Image tmp(zimg, 1);
((Handler*)userdata)->image_callback(tmp);
}
}
}
};
@ -110,6 +115,8 @@ public:
~Image ()
{
if(zbar_image_get_userdata(_img) == this)
zbar_image_set_userdata(_img, NULL);
zbar_image_ref(_img, -1);
}
@ -143,12 +150,7 @@ public:
/// see zbar_image_set_format()
void set_format (const std::string& format)
{
if(format.length() != 4)
throw FormatError();
unsigned long fourcc = ((format[0] & 0xff) |
((format[1] & 0xff) << 8) |
((format[2] & 0xff) << 16) |
((format[3] & 0xff) << 24));
unsigned long fourcc = zbar_fourcc_parse(format.c_str());
zbar_image_set_format(_img, fourcc);
}
@ -183,6 +185,15 @@ public:
return(zbar_image_get_height(_img));
}
/// retrieve both dimensions of the image.
/// see zbar_image_get_size()
/// @since 0.11
void get_size (unsigned &width,
unsigned &height) const
{
zbar_image_get_size(_img, &width, &height);
}
/// specify the pixel size of the image.
/// see zbar_image_set_size()
void set_size (unsigned width,
@ -191,6 +202,26 @@ public:
zbar_image_set_size(_img, width, height);
}
/// retrieve the scan crop rectangle.
/// see zbar_image_get_crop()
void get_crop (unsigned &x,
unsigned &y,
unsigned &width,
unsigned &height) const
{
zbar_image_get_crop(_img, &x, &y, &width, &height);
}
/// set the scan crop rectangle.
/// see zbar_image_set_crop()
void set_crop (unsigned x,
unsigned y,
unsigned width,
unsigned height)
{
zbar_image_set_crop(_img, x, y, width, height);
}
/// return the image sample data.
/// see zbar_image_get_data()
const void *get_data () const
@ -224,6 +255,15 @@ public:
throw FormatError();
}
/// image format conversion.
/// see zbar_image_convert()
/// @since 0.11
Image convert (std::string format) const
{
unsigned long fourcc = zbar_fourcc_parse(format.c_str());
return(convert(fourcc));
}
/// image format conversion with crop/pad.
/// see zbar_image_convert_resize()
/// @since 0.4
@ -278,7 +318,6 @@ protected:
{
// by default nothing is cleaned
assert(img);
assert(zbar_image_get_userdata(img));
}
private:

View File

@ -1,5 +1,5 @@
//------------------------------------------------------------------------
// Copyright 2007-2009 (c) Jeff Brown <spadix@users.sourceforge.net>
// Copyright 2007-2010 (c) Jeff Brown <spadix@users.sourceforge.net>
//
// This file is part of the ZBar Bar Code Reader.
//
@ -183,8 +183,8 @@ class Processor {
void force_format (std::string& input_format,
std::string& output_format)
{
unsigned long ifourcc = *(unsigned long*)input_format.c_str();
unsigned long ofourcc = *(unsigned long*)output_format.c_str();
unsigned long ifourcc = zbar_fourcc_parse(input_format.c_str());
unsigned long ofourcc = zbar_fourcc_parse(output_format.c_str());
if(zbar_processor_force_format(_processor, ifourcc, ofourcc))
throw_exception(_processor);
}

View File

@ -1,5 +1,5 @@
//------------------------------------------------------------------------
// Copyright 2008-2009 (c) Jeff Brown <spadix@users.sourceforge.net>
// Copyright 2008-2010 (c) Jeff Brown <spadix@users.sourceforge.net>
//
// This file is part of the ZBar Bar Code Reader.
//
@ -53,7 +53,7 @@ public:
unsigned width = bpl / 4;
unsigned height = qimg.height();
set_size(width, height);
set_format('B' | ('G' << 8) | ('R' << 16) | ('4' << 24));
set_format(zbar_fourcc('B','G','R','4'));
unsigned long datalen = qimg.numBytes();
set_data(qimg.bits(), datalen);

View File

@ -1,5 +1,5 @@
//------------------------------------------------------------------------
// Copyright 2007-2009 (c) Jeff Brown <spadix@users.sourceforge.net>
// Copyright 2007-2010 (c) Jeff Brown <spadix@users.sourceforge.net>
//
// This file is part of the ZBar Bar Code Reader.
//
@ -64,6 +64,21 @@ public:
ref(-1);
}
/// assignment.
SymbolSet& operator= (const SymbolSet& syms)
{
syms.ref();
ref(-1);
_syms = syms._syms;
return(*this);
}
/// truth testing.
bool operator! () const
{
return(!_syms || !get_size());
}
/// manipulate reference count.
void ref (int delta = 1) const
{
@ -77,7 +92,7 @@ public:
return(_syms);
}
int get_size ()
int get_size () const
{
return((_syms) ? zbar_symbol_set_get_size(_syms) : 0);
}
@ -112,9 +127,16 @@ public:
/// copy constructor.
Point (const Point& pt)
: x(pt.x),
y(pt.y)
{ }
/// assignment.
Point& operator= (const Point& pt)
{
x = pt.x;
y = pt.y;
return(*this);
}
};
@ -129,31 +151,52 @@ public:
: _sym(sym),
_index(index)
{
sym->ref(1);
if(sym)
sym->ref(1);
if(!sym ||
(unsigned)_index >= zbar_symbol_get_loc_size(*_sym))
_index = -1;
}
/// constructor.
/// copy constructor.
PointIterator (const PointIterator& iter)
: _sym(iter._sym),
_index(iter._index)
{
_sym->ref();
if(_sym)
_sym->ref();
}
/// destructor.
~PointIterator ()
{
_sym->ref(-1);
if(_sym)
_sym->ref(-1);
}
/// assignment.
PointIterator& operator= (const PointIterator& iter)
{
if(iter._sym)
iter._sym->ref();
if(_sym)
_sym->ref(-1);
_sym = iter._sym;
_index = iter._index;
return(*this);
}
/// truth testing.
bool operator! () const
{
return(!_sym || _index < 0);
}
/// advance iterator to next Point.
PointIterator& operator++ ()
{
unsigned int i = ++_index;
if(i >= zbar_symbol_get_loc_size(*_sym))
if(!_sym || i >= zbar_symbol_get_loc_size(*_sym))
_index = -1;
return(*this);
}
@ -161,7 +204,9 @@ public:
/// retrieve currently referenced Point.
const Point operator* () const
{
assert(_index >= 0);
assert(!!*this);
if(!*this)
return(Point());
return(Point(zbar_symbol_get_loc_x(*_sym, _index),
zbar_symbol_get_loc_y(*_sym, _index)));
}
@ -213,6 +258,32 @@ public:
ref(-1);
}
/// assignment.
Symbol& operator= (const Symbol& sym)
{
sym.ref(1);
ref(-1);
_sym = sym._sym;
_type = sym._type;
_data = sym._data;
return(*this);
}
Symbol& operator= (const zbar_symbol_t *sym)
{
if(sym)
zbar_symbol_ref(sym, 1);
ref(-1);
init(sym);
return(*this);
}
/// truth testing.
bool operator! () const
{
return(!_sym);
}
void ref (int delta = 1) const
{
if(_sym)
@ -250,6 +321,7 @@ public:
}
/// retrieve the string name for any addon.
/// @deprecated in 0.11
const std::string get_addon_name () const
{
return(zbar_get_addon_name(_type));
@ -269,12 +341,20 @@ public:
/// retrieve inter-frame coherency count.
/// see zbar_symbol_get_count()
/// @since 1.5
/// @since 0.5
int get_count () const
{
return((_sym) ? zbar_symbol_get_count(_sym) : -1);
}
/// retrieve loosely defined relative quality metric.
/// see zbar_symbol_get_quality()
/// @since 0.11
int get_quality () const
{
return((_sym) ? zbar_symbol_get_quality(_sym) : 0);
}
SymbolSet get_components () const
{
return(SymbolSet((_sym) ? zbar_symbol_get_components(_sym) : NULL));
@ -311,6 +391,13 @@ public:
return((_sym) ? zbar_symbol_get_loc_y(_sym, index) : -1);
}
/// see zbar_symbol_get_orientation().
/// @since 0.11
int get_orientation () const
{
return(zbar_symbol_get_orientation(_sym));
}
/// see zbar_symbol_xml().
const std::string xml () const
{
@ -320,9 +407,6 @@ public:
}
protected:
friend class SymbolIterator;
/// (re)initialize Symbol from C symbol object.
void init (const zbar_symbol_t *sym = NULL)
{
@ -361,7 +445,7 @@ public:
{
const zbar_symbol_set_t *zsyms = _syms;
if(zsyms)
_sym.init(zbar_symbol_set_first_symbol(zsyms));
_sym = zbar_symbol_set_first_symbol(zsyms);
}
/// copy constructor.
@ -370,25 +454,33 @@ public:
{
const zbar_symbol_set_t *zsyms = _syms;
if(zsyms)
_sym.init(zbar_symbol_set_first_symbol(zsyms));
_sym = zbar_symbol_set_first_symbol(zsyms);
}
~SymbolIterator ()
{
_sym.init();
}
/// assignment.
SymbolIterator& operator= (const SymbolIterator& iter)
{
_syms = iter._syms;
_sym = iter._sym;
return(*this);
}
bool operator! () const
{
return(!_syms || !_sym);
}
/// advance iterator to next Symbol.
SymbolIterator& operator++ ()
{
const zbar_symbol_t *zsym = _sym;
if(zsym)
_sym.init(zbar_symbol_next(zsym));
else {
const zbar_symbol_set_t *zsyms = _syms;
if(zsyms)
_sym.init(zbar_symbol_set_first_symbol(zsyms));
}
if(!!_sym)
_sym = zbar_symbol_next(_sym);
else if(!!_syms)
_sym = zbar_symbol_set_first_symbol(_syms);
return(*this);
}
@ -440,9 +532,7 @@ inline const SymbolIterator SymbolSet::symbol_end () const {
static inline std::ostream& operator<< (std::ostream& out,
const Symbol& sym)
{
out << sym.get_type_name()
<< sym.get_addon_name()
<< ":" << sym.get_data();
out << sym.get_type_name() << ":" << sym.get_data();
return(out);
}

View File

@ -1,5 +1,5 @@
//------------------------------------------------------------------------
// Copyright 2007-2009 (c) Jeff Brown <spadix@users.sourceforge.net>
// Copyright 2007-2010 (c) Jeff Brown <spadix@users.sourceforge.net>
//
// This file is part of the ZBar Bar Code Reader.
//
@ -92,7 +92,7 @@ public:
/// see zbar_video_init()
void init (std::string& format)
{
unsigned int fourcc = *(unsigned int*)format.c_str();
unsigned int fourcc = zbar_fourcc_parse(format.c_str());
if(zbar_video_init(_video, fourcc))
throw_exception(_video);
}

View File

@ -136,7 +136,7 @@ struct _ZBarGtkClass {
GType zbar_gtk_get_type(void) G_GNUC_CONST;
/**
/**
* zbar_gtk_new:
* create a new barcode reader widget instance.
* initially has no associated video device or image.
@ -189,7 +189,17 @@ void zbar_gtk_set_video_enabled(ZBarGtk *zbar,
*/
gboolean zbar_gtk_get_video_opened(ZBarGtk *zbar);
/**
/** set video camera resolution.
* @width: width in pixels
* @height: height in pixels
*
* @note this call must be made before video is initialized
*/
void zbar_gtk_request_video_size(ZBarGtk *zbar,
int width,
int height);
/**
* utility function to populate a zbar_image_t from a GdkPixbuf.
* @image: the zbar library image destination to populate
* @pixbuf: the GdkPixbuf source

138
iphone/ChangeLog Normal file
View File

@ -0,0 +1,138 @@
version 1.3.1:
* fix examples
- fix EmbedReader initial iPad orientation
- fix TabReader shouldn't show controls
* add retry workaround when device lock fails
- add iPhone 5 launch image to examples
- doc updates
* Lion and Xcode updates
- fix new warnings/errors
- find missing buddy
- fix SDK bg image: force resoution to 72dpi
* Fix EmbedReader example rotation interaction
version 1.2.2:
* reduce controller present and dismiss latency
- add simple shutter to mask video start
version 1.2.1:
* fix overlay resizing bug
version 1.2:
* release updates
version 1.1.3:
* fix UITabViewController rotation interaction
version 1.1.2:
* add maxZoom for increasing zoom range
- workaround camera preview initial location/size bug
* add emulation for UI videoQuality to adjust camera resolution
* fix several simulator-related bugs
- fix device property missing from simulated ZBarReaderView
- fix AVCaptureDevice referenced from ZBarReaderViewController
- fix simulated camera gesture multiple recognition
version 1.1.1:
* fix ReaderSample project path to ZBarSDK
* README document new examples
- make ReaderSample scheme public
* documentation updates
* add emulation for UI camera device and flash mode properties
* workaround orientation bugs in parent controllers
- enable orientation and iPad support for all examples
* add orientation detection fall back
* fix captureReader not exposed to simulator
* fix camera preview stale rotation corner
- fix ZBarReaderViewController toolbar layout accomodation
- switch pre-release samples to use debug library
* update docs to note possible link order dependency
* add missing references to new samples
* add IB support to ZBarReaderViewController
- add tabbed reader sample
* add embedded reader sample
- factor out camera simulation logic
* fix readertest max quality result filtering
- thanks to John Boydon for finding this!
* improve support for resizing, rotating and embedding the reader
* add readertest fixed zoom stops
* add manual frame capture
- readertest save as PNG
* enhance readertest to support default/demo pre-config and distribution
* updates for Xcode 4
* expose tracking box color
version 1.1:
* fix doc typo (bug #3139087)
- add modifier bit docs
version 1.0.1:
* hotfix broken ZBarHelpController back button
* release updates
- update docs
* fix support for GS1 AIs
* fix simulated camera image orientation/scaling
* cleanup and expose ZBarHelpController
* expose enable for reader capture processing
* workaround iOS 4.2 hang
- update to use latest SDK
* add support for Code 93 symbology
version 1.0:
* update to SDK 4.1, clean out LLVM warnings
* fix camera simulation gesture
version 0.1.2:
* fix missing header dependency
* doc enhancements
* force controls to front when showsZBarControls is enabled
* fix initial zoom crop (performance bug)
* workaround iPhone quartz access past image data
version 0.1.1:
* migrate to binary iPhone SDK distribution (NB backward incompatibilities!)
- restructure headers
version 0.1:
* workaround for iPhone simulator builds
- refactor ZBarReaderView for capture/simulator specific implementations
- fix tracking calculations
- fix captured video frame color conversion
* fix for poor iPhone 4 performance
* enable torch for iPhone 4
* fix iPhone circular ref bug
* add iPhone cache flush, change new libs to weak refs
* fix iPhone async ref bug
* enhance iPhone readertest w/more options
* add iPhone zoom support, integrate with crop
* add iPhone OS 4.0 video capture support
- replacement view controller for new camera reader
- separate view for use without controller
- separate capture delegate for use standalone
- add continuous autofocus
* cleanup and expose iphone help display API
* fixes to new iphone help display
* migrate iphone help display to integrated web page (NB resource updates!)
- allows easier customization
- local links open directly, external links confirm and jump out to Safari
- JavaScript hook for help context customization
- also enhanced default help (note this changes the required resources)
- fix to disable scanning during help overlay
- thanks to iafanasyev and others for detailed suggestions
* fix iphone custom overlay response (bug #2959617)
- thanks to an anonymous user for the patch!
* iphone widget performance tuning enhancements
- fix crop calculation bug in ZBarImage
- add properties to control pre-scan image cropping and scaling
- add property for scanner cache control
- enable some scanner density control (FIXME should be property)
- fix ifdef for quality control (FIXME should be property)
- add "sequence" mode test (not actually so useful)
* realtime scanning for iphone widget
- uses UIGetScreenImage() (NB private)
- ZBarImage from CGImage (instead of UIImage)
- add crop to scaling step
- expose symbol set unfiltered results
* iphone widget back compat updates, add basic test app
* add Obj-C wrapper
* first pass working iPhone "widget"

66
iphone/README Normal file
View File

@ -0,0 +1,66 @@
ZBar iOS SDK
============
ZBar Bar Code Reader is an open source software suite for reading bar
codes from various sources, such as video streams, image files and raw
intensity sensors. It supports EAN-13/UPC-A, UPC-E, EAN-8, DataBar,
Code 128, Code 93, Code 39, Codabar, Interleaved 2 of 5 and QR Code.
These are the Objective C wrappers and integrated widget for developing
with the library on the iOS platform.
Check the ZBar project home page for the latest release, forums, etc.
* http://zbar.sourceforge.net/iphone
Installation
------------
If you are migrating from a pre-SDK source version of the library,
first make sure you remove all of the old references to zbar.xcodeproj
and libzbar.a and revert any related build settings.
To add the SDK to an Xcode project:
1. Drag ZBarSDK into your Xcode project.
3. Add these system frameworks to your project:
* AVFoundation.framework (weak)
* CoreMedia.framework (weak)
* CoreVideo.framework (weak)
* QuartzCore.framework
* libiconv.dylib
Documentation
-------------
See Documentation.html for complete SDK documentation.
Examples
--------
You should be able to open and build the examples directly from the
disk image (ignore warnings about the read-only volume). If you have
problems with this, please copy the examples to your local drive
instead and build from there.
A tutorial that walks through installing and using the SDK is
available in the documentation. The SDK disk image also contains the
resulting Xcode project at Examples/ReaderSample.
Examples/readertest demonstrates most of the configuration options
available for the reader.
Examples/TabReader shows how you can use Interface Builder to add the
reader as a tab in a UITabBarController.
Examples/EmbedReader shows how a ZBarReaderView may be embedded
directly in the application view hierarchy.
Copyright and License
---------------------
Licensed under the GNU Lesser General Public License, version 2.1.
http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt
Copyright 2008-2011 © Jeff Brown <spadix@users.sourceforge.net> et al
See the included files COPYING and LICENSE for details

43
iphone/ZBarCVImage.h Normal file
View File

@ -0,0 +1,43 @@
//------------------------------------------------------------------------
// Copyright 2010 (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
//------------------------------------------------------------------------
#import <ZBarSDK/ZBarImage.h>
#import <CoreVideo/CoreVideo.h>
// ZBarImage referring to a CVPixelBuffer. used internally to handle
// asynchronous conversion to UIImage
@interface ZBarCVImage
: ZBarImage
{
CVPixelBufferRef pixelBuffer;
void *rgbBuffer;
NSInvocationOperation *conversion;
}
- (void) waitUntilConverted;
@property (nonatomic) CVPixelBufferRef pixelBuffer;
@property (nonatomic, readonly) void *rgbBuffer;
@end

195
iphone/ZBarCVImage.m Normal file
View File

@ -0,0 +1,195 @@
//------------------------------------------------------------------------
// Copyright 2010 (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
//------------------------------------------------------------------------
#import "ZBarCVImage.h"
#define MODULE ZBarCVImage
#import "debug.h"
static NSOperationQueue *conversionQueue;
static const void*
asyncProvider_getBytePointer (void *info)
{
// block until data is available
ZBarCVImage *image = info;
assert(image);
[image waitUntilConverted];
void *buf = image.rgbBuffer;
assert(buf);
return(buf);
}
static const CGDataProviderDirectCallbacks asyncProvider = {
.version = 0,
.getBytePointer = asyncProvider_getBytePointer,
.releaseBytePointer = NULL,
.getBytesAtPosition = NULL,
.releaseInfo = (void*)CFRelease,
};
@implementation ZBarCVImage
@synthesize pixelBuffer, rgbBuffer;
- (void) dealloc
{
self.pixelBuffer = NULL;
if(rgbBuffer) {
free(rgbBuffer);
rgbBuffer = NULL;
}
[conversion release];
conversion = nil;
[super dealloc];
}
- (void) setPixelBuffer: (CVPixelBufferRef) newbuf
{
CVPixelBufferRef oldbuf = pixelBuffer;
if(newbuf)
CVPixelBufferRetain(newbuf);
pixelBuffer = newbuf;
if(oldbuf)
CVPixelBufferRelease(oldbuf);
}
- (void) waitUntilConverted
{
// operation will at least have been queued already
NSOperation *op = [conversion retain];
if(!op)
return;
[op waitUntilFinished];
[op release];
}
- (UIImage*) UIImageWithOrientation: (UIImageOrientation) orient
{
if(!conversion && !rgbBuffer) {
// start format conversion in separate thread
NSOperationQueue *queue = conversionQueue;
if(!queue) {
queue = conversionQueue = [NSOperationQueue new];
queue.maxConcurrentOperationCount = 1;
}
else
[queue waitUntilAllOperationsAreFinished];
conversion = [[NSInvocationOperation alloc]
initWithTarget: self
selector: @selector(convertCVtoRGB)
object: nil];
[queue addOperation: conversion];
[conversion release];
}
// create UIImage before converted data is available
CGSize size = self.size;
int w = size.width;
int h = size.height;
CGDataProviderRef datasrc =
CGDataProviderCreateDirect([self retain], 3 * w * h, &asyncProvider);
CGColorSpaceRef cs = CGColorSpaceCreateDeviceRGB();
CGImageRef cgimg =
CGImageCreate(w, h, 8, 24, 3 * w, cs,
kCGBitmapByteOrderDefault, datasrc,
NULL, YES, kCGRenderingIntentDefault);
CGColorSpaceRelease(cs);
CGDataProviderRelease(datasrc);
UIImage *uiimg =
[UIImage imageWithCGImage: cgimg
scale: 1
orientation: orient];
CGImageRelease(cgimg);
return(uiimg);
}
// convert video frame to a CGImage compatible RGB format
// FIXME this is temporary until we can find the native way...
- (void) convertCVtoRGB
{
timer_start;
unsigned long format = self.format;
assert(format == zbar_fourcc('C','V','2','P'));
if(format != zbar_fourcc('C','V','2','P'))
return;
CVPixelBufferLockBaseAddress(pixelBuffer, kCVPixelBufferLock_ReadOnly);
int w = CVPixelBufferGetWidth(pixelBuffer);
int h = CVPixelBufferGetHeight(pixelBuffer);
int dy = CVPixelBufferGetBytesPerRowOfPlane(pixelBuffer, 0);
int duv = CVPixelBufferGetBytesPerRowOfPlane(pixelBuffer, 1);
uint8_t *py = CVPixelBufferGetBaseAddressOfPlane(pixelBuffer, 0);
uint8_t *puv = CVPixelBufferGetBaseAddressOfPlane(pixelBuffer, 1);
if(!py || !puv || dy < w || duv < w)
goto error;
int datalen = 3 * w * h;
// Quartz accesses some undocumented amount past allocated data?
// ...allocate extra to compensate
uint8_t *pdst = rgbBuffer = malloc(datalen + 3 * w);
if(!pdst)
goto error;
[self setData: rgbBuffer
withLength: datalen];
for(int y = 0; y < h; y++) {
const uint8_t *qy = py;
const uint8_t *quv = puv;
for(int x = 0; x < w; x++) {
int Y1 = *(qy++) - 16;
int Cb = *(quv) - 128;
int Cr = *(quv + 1) - 128;
Y1 *= 4769;
quv += (x & 1) << 1;
int r = (Y1 + 6537 * Cr + 2048) / 4096;
int g = (Y1 - 1604 * Cb - 3329 * Cr + 2048) / 4096;
int b = (Y1 + 8263 * Cb + 2048) / 4096;
r = (r | -!!(r >> 8)) & -((r >> 8) >= 0);
g = (g | -!!(g >> 8)) & -((g >> 8) >= 0);
b = (b | -!!(b >> 8)) & -((b >> 8) >= 0);
*(pdst++) = r;
*(pdst++) = g;
*(pdst++) = b;
}
py += dy;
if(y & 1)
puv += duv;
}
error:
CVPixelBufferUnlockBaseAddress(pixelBuffer, kCVPixelBufferLock_ReadOnly);
zlog(@"convert time %gs", timer_elapsed(t_start, timer_now()));
// release buffer as soon as conversion is complete
self.pixelBuffer = NULL;
conversion = nil;
}
@end

View File

@ -0,0 +1,120 @@
//------------------------------------------------------------------------
// Copyright 2010-2011 (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
//------------------------------------------------------------------------
#import <ZBarSDK/ZBarCameraSimulator.h>
#import <ZBarSDK/ZBarReaderView.h>
// hack around missing simulator support for AVCapture interfaces
@implementation ZBarCameraSimulator
@synthesize readerView;
- (id) initWithViewController: (UIViewController*) vc
{
if(!TARGET_IPHONE_SIMULATOR) {
[self release];
return(nil);
}
self = [super init];
if(!self)
return(nil);
viewController = vc;
return(self);
}
- (void) dealloc
{
viewController = nil;
readerView = nil;
[picker release];
picker = nil;
[pickerPopover release];
pickerPopover = nil;
[super dealloc];
}
- (void) setReaderView: (ZBarReaderView*) view
{
ZBarReaderView *oldView = readerView;
readerView = [view retain];
[oldView release];
UILongPressGestureRecognizer *gesture =
[[UILongPressGestureRecognizer alloc]
initWithTarget: self
action: @selector(didLongPress:)];
gesture.numberOfTouchesRequired = 2;
[view addGestureRecognizer: gesture];
[gesture release];
}
- (void) didLongPress: (UILongPressGestureRecognizer*) gesture
{
if(gesture.state == UIGestureRecognizerStateBegan)
[self takePicture];
}
- (void) takePicture
{
if(!picker) {
picker = [UIImagePickerController new];
picker.delegate = self;
}
if(UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad) {
if(!pickerPopover)
pickerPopover = [[UIPopoverController alloc]
initWithContentViewController: picker];
[pickerPopover presentPopoverFromRect: CGRectZero
inView: readerView
permittedArrowDirections: UIPopoverArrowDirectionAny
animated: YES];
}
else
[viewController presentModalViewController: picker
animated: YES];
}
- (void) imagePickerController: (UIImagePickerController*) _picker
didFinishPickingMediaWithInfo: (NSDictionary*) info
{
UIImage *image = [info objectForKey: UIImagePickerControllerOriginalImage];
if(UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad)
[pickerPopover dismissPopoverAnimated: YES];
else
[_picker dismissModalViewControllerAnimated: YES];
[readerView performSelector: @selector(scanImage:)
withObject: image
afterDelay: .1];
}
- (void) imagePickerControllerDidCancel: (UIImagePickerController*) _picker
{
[_picker dismissModalViewControllerAnimated: YES];
}
@end

370
iphone/ZBarCaptureReader.m Normal file
View File

@ -0,0 +1,370 @@
//------------------------------------------------------------------------
// Copyright 2010 (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
//------------------------------------------------------------------------
#import <libkern/OSAtomic.h>
#import <AVFoundation/AVFoundation.h>
#import <CoreMedia/CoreMedia.h>
#import <CoreVideo/CoreVideo.h>
#import <ZBarSDK/ZBarCaptureReader.h>
#import <ZBarSDK/ZBarImageScanner.h>
#import "ZBarCVImage.h"
#define MODULE ZBarCaptureReader
#import "debug.h"
enum {
STOPPED = 0,
RUNNING = 1,
PAUSED = 2,
CAPTURE = 4,
};
@implementation ZBarCaptureReader
@synthesize captureOutput, captureDelegate, scanner, scanCrop, size,
framesPerSecond, enableCache;
@dynamic enableReader;
- (void) initResult
{
[result release];
result = [ZBarCVImage new];
result.format = [ZBarImage fourcc: @"CV2P"];
}
- (id) initWithImageScanner: (ZBarImageScanner*) _scanner
{
self = [super init];
if(!self)
return(nil);
t_fps = t_frame = timer_now();
enableCache = YES;
scanner = [_scanner retain];
scanCrop = CGRectMake(0, 0, 1, 1);
image = [ZBarImage new];
image.format = [ZBarImage fourcc: @"Y800"];
[self initResult];
captureOutput = [AVCaptureVideoDataOutput new];
captureOutput.alwaysDiscardsLateVideoFrames = YES;
#ifdef FIXED_8697526
/* iOS 4.2 introduced a bug that causes [session startRunning] to
* hang if the session has a preview layer and this property is
* specified at the output. As this happens to be the default
* setting for the currently supported devices, it can be omitted
* without causing a functional problem (for now...). Of course,
* we still have no idea what the real problem is, or how robust
* this is as a workaround...
*/
captureOutput.videoSettings =
[NSDictionary
dictionaryWithObject:
[NSNumber numberWithInt:
kCVPixelFormatType_420YpCbCr8BiPlanarVideoRange]
forKey: (NSString*)kCVPixelBufferPixelFormatTypeKey];
#endif
queue = dispatch_queue_create("ZBarCaptureReader", NULL);
[captureOutput setSampleBufferDelegate:
(id<AVCaptureVideoDataOutputSampleBufferDelegate>)self
queue: queue];
return(self);
}
- (id) init
{
self = [self initWithImageScanner:
[[ZBarImageScanner new]
autorelease]];
if(!self)
return(nil);
[scanner setSymbology: 0
config: ZBAR_CFG_X_DENSITY
to: 3];
[scanner setSymbology: 0
config: ZBAR_CFG_Y_DENSITY
to: 3];
return(self);
}
- (void) dealloc
{
captureDelegate = nil;
// queue continues to run after stopping (NB even after DidStopRunning!);
// ensure released delegate is not called. (also NB that the queue
// may not be null, even in this case...)
[captureOutput setSampleBufferDelegate: nil
queue: queue];
[captureOutput release];
captureOutput = nil;
dispatch_release(queue);
[image release];
image = nil;
[result release];
result = nil;
[scanner release];
scanner = nil;
[super dealloc];
}
- (BOOL) enableReader
{
return(OSAtomicOr32Barrier(0, &state) & RUNNING);
}
- (void) setEnableReader: (BOOL) enable
{
if(!enable)
OSAtomicAnd32Barrier(STOPPED, &state);
else if(!(OSAtomicOr32OrigBarrier(RUNNING, &state) & RUNNING)) {
OSAtomicAnd32Barrier(~PAUSED, &state);
@synchronized(scanner) {
scanner.enableCache = enableCache;
}
}
}
- (void) willStartRunning
{
self.enableReader = YES;
}
- (void) willStopRunning
{
self.enableReader = NO;
}
- (void) flushCache
{
@synchronized(scanner) {
scanner.enableCache = enableCache;
}
}
- (void) captureFrame
{
OSAtomicOr32(CAPTURE, &state);
}
- (void) setCaptureDelegate: (id<ZBarCaptureDelegate>) delegate
{
@synchronized(scanner) {
captureDelegate = delegate;
}
}
- (void) cropUpdate
{
@synchronized(scanner) {
image.crop = CGRectMake(scanCrop.origin.x * width,
scanCrop.origin.y * height,
scanCrop.size.width * width,
scanCrop.size.height * height);
}
}
- (void) setScanCrop: (CGRect) crop
{
if(CGRectEqualToRect(scanCrop, crop))
return;
scanCrop = crop;
[self cropUpdate];
}
- (void) didTrackSymbols: (ZBarSymbolSet*) syms
{
[captureDelegate
captureReader: self
didTrackSymbols: syms];
}
- (void) didReadNewSymbolsFromImage: (ZBarImage*) img
{
timer_start;
[captureDelegate
captureReader: self
didReadNewSymbolsFromImage: img];
OSAtomicAnd32Barrier(~PAUSED, &state);
zlog(@"latency: delegate=%gs total=%gs",
timer_elapsed(t_start, timer_now()),
timer_elapsed(t_scan, timer_now()));
}
- (void) setFramesPerSecond: (CGFloat) fps
{
framesPerSecond = fps;
}
- (void) updateFPS: (NSNumber*) val
{
[self setFramesPerSecond: val.doubleValue];
}
- (void) setSize: (CGSize) _size
{
size = _size;
}
- (void) updateSize: (CFDictionaryRef) val
{
CGSize _size;
if(CGSizeMakeWithDictionaryRepresentation(val, &_size))
[self setSize: _size];
}
- (void) captureOutput: (AVCaptureOutput*) output
didOutputSampleBuffer: (CMSampleBufferRef) samp
fromConnection: (AVCaptureConnection*) conn
{
// queue is apparently not flushed when stopping;
// only process when running
uint32_t _state = OSAtomicOr32Barrier(0, &state);
if((_state & (PAUSED | RUNNING)) != RUNNING)
return;
NSAutoreleasePool *pool = [NSAutoreleasePool new];
image.sequence = framecnt++;
uint64_t now = timer_now();
double dt = timer_elapsed(t_frame, now);
t_frame = now;
if(dt > 2) {
t_fps = now;
dt_frame = 0;
}
else if(!dt_frame)
dt_frame = dt;
dt_frame = (dt_frame + dt) / 2;
if(timer_elapsed(t_fps, now) >= 1) {
[self performSelectorOnMainThread: @selector(updateFPS:)
withObject: [NSNumber numberWithDouble: 1 / dt_frame]
waitUntilDone: NO];
t_fps = now;
}
CVImageBufferRef buf = CMSampleBufferGetImageBuffer(samp);
if(CMSampleBufferGetNumSamples(samp) != 1 ||
!CMSampleBufferIsValid(samp) ||
!CMSampleBufferDataIsReady(samp) ||
!buf) {
zlog(@"ERROR: invalid sample");
goto error;
}
OSType format = CVPixelBufferGetPixelFormatType(buf);
int planes = CVPixelBufferGetPlaneCount(buf);
if(format != kCVPixelFormatType_420YpCbCr8BiPlanarVideoRange ||
!planes) {
zlog(@"ERROR: invalid buffer format");
goto error;
}
int w = CVPixelBufferGetBytesPerRowOfPlane(buf, 0);
int h = CVPixelBufferGetHeightOfPlane(buf, 0);
CVReturn rc =
CVPixelBufferLockBaseAddress(buf, kCVPixelBufferLock_ReadOnly);
if(!w || !h || rc) {
zlog(@"ERROR: invalid buffer data");
goto error;
}
void *data = CVPixelBufferGetBaseAddressOfPlane(buf, 0);
if(data) {
[image setData: data
withLength: w * h];
BOOL doTrack = NO;
int ngood = 0;
ZBarSymbolSet *syms = nil;
@synchronized(scanner) {
if(width != w || height != h) {
width = w;
height = h;
CGSize _size = CGSizeMake(w, h);
CFDictionaryRef sized =
CGSizeCreateDictionaryRepresentation(_size);
if(sized) {
[self performSelectorOnMainThread: @selector(updateSize:)
withObject: (id)sized
waitUntilDone: NO];
CFRelease(sized);
}
image.size = _size;
[self cropUpdate];
}
ngood = [scanner scanImage: image];
syms = scanner.results;
doTrack = [captureDelegate respondsToSelector:
@selector(captureReader:didTrackSymbols:)];
}
now = timer_now();
if(ngood >= 0) {
// return unfiltered results for tracking feedback
syms.filterSymbols = NO;
int nraw = syms.count;
if(nraw > 0 || (_state & CAPTURE))
zlog(@"scan image: %dx%d crop=%@ ngood=%d nraw=%d st=%d",
w, h, NSStringFromCGRect(image.crop), ngood, nraw, _state);
if(ngood || (_state & CAPTURE)) {
// copy image data so we can release the buffer
result.size = CGSizeMake(w, h);
result.pixelBuffer = buf;
result.symbols = syms;
t_scan = now;
OSAtomicXor32Barrier((_state & CAPTURE) | PAUSED, &state);
[self performSelectorOnMainThread:
@selector(didReadNewSymbolsFromImage:)
withObject: result
waitUntilDone: NO];
[self initResult];
}
if(nraw && doTrack)
[self performSelectorOnMainThread:
@selector(didTrackSymbols:)
withObject: syms
waitUntilDone: NO];
}
[image setData: NULL
withLength: 0];
}
else
zlog(@"ERROR: invalid data");
CVPixelBufferUnlockBaseAddress(buf, kCVPixelBufferLock_ReadOnly);
error:
[pool release];
}
@end

267
iphone/ZBarHelpController.m Normal file
View File

@ -0,0 +1,267 @@
//------------------------------------------------------------------------
// Copyright 2009-2010 (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
//------------------------------------------------------------------------
#import <ZBarSDK/ZBarHelpController.h>
#define MODULE ZBarHelpController
#import "debug.h"
@implementation ZBarHelpController
@synthesize delegate;
- (id) initWithReason: (NSString*) _reason
{
self = [super init];
if(!self)
return(nil);
if(!_reason)
_reason = @"INFO";
reason = [_reason retain];
return(self);
}
- (id) init
{
return([self initWithReason: nil]);
}
- (void) cleanup
{
[toolbar release];
toolbar = nil;
[webView release];
webView = nil;
[doneBtn release];
doneBtn = nil;
[backBtn release];
backBtn = nil;
[space release];
space = nil;
}
- (void) dealloc
{
[self cleanup];
[reason release];
reason = nil;
[linkURL release];
linkURL = nil;
[super dealloc];
}
- (void) viewDidLoad
{
[super viewDidLoad];
UIView *view = self.view;
CGRect bounds = self.view.bounds;
if(!bounds.size.width || !bounds.size.height)
view.frame = bounds = CGRectMake(0, 0, 320, 480);
view.backgroundColor = [UIColor colorWithWhite: .125f
alpha: 1];
view.autoresizingMask = (UIViewAutoresizingFlexibleWidth |
UIViewAutoresizingFlexibleHeight);
webView = [[UIWebView alloc]
initWithFrame: CGRectMake(0, 0,
bounds.size.width,
bounds.size.height - 44)];
webView.delegate = self;
webView.backgroundColor = [UIColor colorWithWhite: .125f
alpha: 1];
webView.autoresizingMask = (UIViewAutoresizingFlexibleWidth |
UIViewAutoresizingFlexibleHeight |
UIViewAutoresizingFlexibleBottomMargin);
webView.hidden = YES;
[view addSubview: webView];
toolbar = [[UIToolbar alloc]
initWithFrame: CGRectMake(0, bounds.size.height - 44,
bounds.size.width, 44)];
toolbar.barStyle = UIBarStyleBlackOpaque;
toolbar.autoresizingMask = (UIViewAutoresizingFlexibleWidth |
UIViewAutoresizingFlexibleHeight |
UIViewAutoresizingFlexibleTopMargin);
doneBtn = [[UIBarButtonItem alloc]
initWithBarButtonSystemItem: UIBarButtonSystemItemDone
target: self
action: @selector(dismiss)];
backBtn = [[UIBarButtonItem alloc]
initWithImage: [UIImage imageNamed: @"zbar-back.png"]
style: UIBarButtonItemStylePlain
target: webView
action: @selector(goBack)];
space = [[UIBarButtonItem alloc]
initWithBarButtonSystemItem:
UIBarButtonSystemItemFlexibleSpace
target: nil
action: nil];
toolbar.items = [NSArray arrayWithObjects: space, doneBtn, nil];
[view addSubview: toolbar];
NSString *path = [[NSBundle mainBundle]
pathForResource: @"zbar-help"
ofType: @"html"];
NSURLRequest *req = nil;
if(path) {
NSURL *url = [NSURL fileURLWithPath: path
isDirectory: NO];
if(url)
req = [NSURLRequest requestWithURL: url];
}
if(req)
[webView loadRequest: req];
else
NSLog(@"ERROR: unable to load zbar-help.html from bundle");
}
- (void) viewDidUnload
{
[self cleanup];
[super viewDidUnload];
}
- (void) viewWillAppear: (BOOL) animated
{
assert(webView);
if(webView.loading)
webView.hidden = YES;
webView.delegate = self;
[super viewWillAppear: animated];
}
- (void) viewWillDisappear: (BOOL) animated
{
[webView stopLoading];
webView.delegate = nil;
[super viewWillDisappear: animated];
}
- (BOOL) shouldAutorotateToInterfaceOrientation: (UIInterfaceOrientation) orient
{
return([self isInterfaceOrientationSupported: orient]);
}
- (void) willAnimateRotationToInterfaceOrientation: (UIInterfaceOrientation) orient
duration: (NSTimeInterval) duration
{
[webView reload];
}
- (void) didRotateFromInterfaceOrientation: (UIInterfaceOrientation) orient
{
zlog(@"frame=%@ webView.frame=%@ toolbar.frame=%@",
NSStringFromCGRect(self.view.frame),
NSStringFromCGRect(webView.frame),
NSStringFromCGRect(toolbar.frame));
}
- (BOOL) isInterfaceOrientationSupported: (UIInterfaceOrientation) orient
{
UIViewController *parent = self.parentViewController;
if(parent && !orientations)
return([parent shouldAutorotateToInterfaceOrientation: orient]);
return((orientations >> orient) & 1);
}
- (void) setInterfaceOrientation: (UIInterfaceOrientation) orient
supported: (BOOL) supported
{
NSUInteger mask = 1 << orient;
if(supported)
orientations |= mask;
else
orientations &= ~mask;
}
- (void) dismiss
{
if([delegate respondsToSelector: @selector(helpControllerDidFinish:)])
[delegate helpControllerDidFinish: self];
else
[self dismissModalViewControllerAnimated: YES];
}
- (void) webViewDidFinishLoad: (UIWebView*) view
{
if(view.hidden) {
[view stringByEvaluatingJavaScriptFromString:
[NSString stringWithFormat:
@"onZBarHelp({reason:\"%@\"});", reason]];
[UIView beginAnimations: @"ZBarHelp"
context: nil];
view.hidden = NO;
[UIView commitAnimations];
}
BOOL canGoBack = [view canGoBack];
NSArray *items = toolbar.items;
if(canGoBack != ([items objectAtIndex: 0] == backBtn)) {
if(canGoBack)
items = [NSArray arrayWithObjects: backBtn, space, doneBtn, nil];
else
items = [NSArray arrayWithObjects: space, doneBtn, nil];
[toolbar setItems: items
animated: YES];
}
}
- (BOOL) webView: (UIWebView*) view
shouldStartLoadWithRequest: (NSURLRequest*) req
navigationType: (UIWebViewNavigationType) nav
{
NSURL *url = [req URL];
if([url isFileURL])
return(YES);
linkURL = [url retain];
UIAlertView *alert =
[[UIAlertView alloc]
initWithTitle: @"Open External Link"
message: @"Close this application and open link in Safari?"
delegate: nil
cancelButtonTitle: @"Cancel"
otherButtonTitles: @"OK", nil];
alert.delegate = self;
[alert show];
[alert release];
return(NO);
}
- (void) alertView: (UIAlertView*) view
clickedButtonAtIndex: (NSInteger) idx
{
if(idx)
[[UIApplication sharedApplication]
openURL: linkURL];
}
@end

306
iphone/ZBarImage.m Normal file
View File

@ -0,0 +1,306 @@
//------------------------------------------------------------------------
// Copyright 2009-2010 (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
//------------------------------------------------------------------------
#import <UIKit/UIKit.h>
#import <ZBarSDK/ZBarImage.h>
#import "debug.h"
static void image_cleanup(zbar_image_t *zimg)
{
ZBarImage *image = zbar_image_get_userdata(zimg);
[image cleanup];
}
@implementation ZBarImage
@dynamic format, sequence, size, crop, data, dataLength, symbols, zbarImage,
UIImage;
+ (unsigned long) fourcc: (NSString*) format
{
return(zbar_fourcc_parse([format UTF8String]));
}
- (id) initWithImage: (zbar_image_t*) image
{
if(!image) {
[self release];
return(nil);
}
if(self = [super init]) {
zimg = image;
zbar_image_ref(image, 1);
zbar_image_set_userdata(zimg, self);
}
return(self);
}
- (id) init
{
zbar_image_t *image = zbar_image_create();
self = [self initWithImage: image];
zbar_image_ref(image, -1);
return(self);
}
- (void) dealloc
{
if(zimg) {
zbar_image_ref(zimg, -1);
zimg = NULL;
}
[super dealloc];
}
- (id) initWithCGImage: (CGImageRef) image
crop: (CGRect) crop
size: (CGSize) size
{
if(!(self = [self init]))
return(nil);
uint64_t t_start = timer_now();
unsigned int w = size.width + 0.5;
unsigned int h = size.height + 0.5;
unsigned long datalen = w * h;
uint8_t *raw = malloc(datalen);
if(!raw) {
[self release];
return(nil);
}
zbar_image_set_data(zimg, raw, datalen, zbar_image_free_data);
zbar_image_set_format(zimg, zbar_fourcc('Y','8','0','0'));
zbar_image_set_size(zimg, w, h);
// scale and crop simultaneously
CGFloat scale = size.width / crop.size.width;
crop.origin.x *= -scale;
crop.size.width = scale * (CGFloat)CGImageGetWidth(image);
scale = size.height / crop.size.height;
CGFloat height = CGImageGetHeight(image);
// compensate for wacky origin
crop.origin.y = height - crop.origin.y - crop.size.height;
crop.origin.y *= -scale;
crop.size.height = scale * height;
// generate grayscale image data
CGColorSpaceRef cs = CGColorSpaceCreateDeviceGray();
CGContextRef ctx =
CGBitmapContextCreate(raw, w, h, 8, w, cs, kCGImageAlphaNone);
CGColorSpaceRelease(cs);
CGContextSetAllowsAntialiasing(ctx, 0);
CGContextDrawImage(ctx, crop, image);
#if 0
zlog(@"convert image %dx%d: crop %g,%g %gx%g size %gx%g (%dx%d)",
CGImageGetWidth(image), CGImageGetHeight(image),
crop.origin.x, crop.origin.y, crop.size.width, crop.size.height,
size.width, size.height, w, h);
CGImageRef cgdump = CGBitmapContextCreateImage(ctx);
UIImage *uidump = [[UIImage alloc]
initWithCGImage: cgdump];
CGImageRelease(cgdump);
UIImageWriteToSavedPhotosAlbum(uidump, nil, nil, NULL);
[uidump release];
#endif
CGContextRelease(ctx);
t_convert = timer_elapsed(t_start, timer_now());
return(self);
}
- (id) initWithCGImage: (CGImageRef) image
size: (CGSize) size
{
CGRect crop = CGRectMake(0, 0,
CGImageGetWidth(image),
CGImageGetHeight(image));
return([self initWithCGImage: image
crop: crop
size: size]);
}
- (id) initWithCGImage: (CGImageRef) image
{
CGRect crop = CGRectMake(0, 0,
CGImageGetWidth(image),
CGImageGetHeight(image));
return([self initWithCGImage: image
crop: crop
size: crop.size]);
}
- (zbar_image_t*) image
{
return(zimg);
}
- (unsigned long) format
{
return(zbar_image_get_format(zimg));
}
- (void) setFormat: (unsigned long) format
{
zbar_image_set_format(zimg, format);
}
- (unsigned) sequence
{
return(zbar_image_get_sequence(zimg));
}
- (void) setSequence: (unsigned) seq
{
zbar_image_set_sequence(zimg, seq);
}
- (CGSize) size
{
unsigned w, h;
zbar_image_get_size(zimg, &w, &h);
return(CGSizeMake(w, h));
}
- (void) setSize: (CGSize) size
{
zbar_image_set_size(zimg, size.width + .5, size.height + .5);
}
- (CGRect) crop
{
unsigned x, y, w, h;
zbar_image_get_crop(zimg, &x, &y, &w, &h);
return(CGRectMake(x, y, w, h));
}
- (void) setCrop: (CGRect) crop
{
zbar_image_set_crop(zimg, crop.origin.x + .5, crop.origin.y + .5,
crop.size.width + .5, crop.size.height + .5);
}
- (ZBarSymbolSet*) symbols
{
return([[[ZBarSymbolSet alloc]
initWithSymbolSet: zbar_image_get_symbols(zimg)]
autorelease]);
}
- (void) setSymbols: (ZBarSymbolSet*) symbols
{
zbar_image_set_symbols(zimg, [symbols zbarSymbolSet]);
}
- (const void*) data
{
return(zbar_image_get_data(zimg));
}
- (unsigned long) dataLength
{
return(zbar_image_get_data_length(zimg));
}
- (void) setData: (const void*) data
withLength: (unsigned long) length
{
zbar_image_set_data(zimg, data, length, image_cleanup);
}
- (zbar_image_t*) zbarImage
{
return(zimg);
}
- (UIImage*) UIImageWithOrientation: (UIImageOrientation) orient
{
unsigned long format = self.format;
size_t bpc, bpp;
switch(format)
{
case zbar_fourcc('R','G','B','3'):
bpc = 8;
bpp = 24;
break;
case zbar_fourcc('R','G','B','4'):
bpc = 8;
bpp = 32;
break;
case zbar_fourcc('R','G','B','Q'):
bpc = 5;
bpp = 16;
break;
default:
NSLog(@"ERROR: format %.4s(%08lx) is unsupported",
(char*)&format, format);
assert(0);
return(nil);
};
unsigned w = zbar_image_get_width(zimg);
unsigned h = zbar_image_get_height(zimg);
const void *data = zbar_image_get_data(zimg);
size_t datalen = zbar_image_get_data_length(zimg);
CGDataProviderRef datasrc =
CGDataProviderCreateWithData(self, data, datalen, (void*)CFRelease);
CGColorSpaceRef cs = CGColorSpaceCreateDeviceRGB();
CGImageRef cgimg =
CGImageCreate(w, h, bpc, bpp, ((bpp + 7) >> 3) * w, cs,
kCGBitmapByteOrderDefault |
kCGImageAlphaNoneSkipFirst,
datasrc, NULL, YES, kCGRenderingIntentDefault);
CGColorSpaceRelease(cs);
CGDataProviderRelease(datasrc);
UIImage *uiimg =
[UIImage imageWithCGImage: cgimg
scale: 1
orientation: orient];
CGImageRelease(cgimg);
return(uiimg);
}
- (UIImage*) UIImage
{
return([self UIImageWithOrientation: UIImageOrientationUp]);
}
- (void) cleanup
{
}
#if 0
- (ZBarImage*) convertToFormat: (unsigned long) format
{
zbar_image_t *zdst = zbar_image_convert(zimg, format);
ZBarImage *image = ;
return([[[ZBarImage alloc] initWithImage: zdst] autorelease]);
}
#endif
@end

85
iphone/ZBarImageScanner.m Normal file
View File

@ -0,0 +1,85 @@
//------------------------------------------------------------------------
// 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
//------------------------------------------------------------------------
#import <ZBarSDK/ZBarImageScanner.h>
#import "debug.h"
@implementation ZBarImageScanner
@dynamic enableCache, results;
- (id) init
{
if(self = [super init]) {
scanner = zbar_image_scanner_create();
}
return(self);
}
- (void) dealloc
{
if(scanner) {
zbar_image_scanner_destroy(scanner);
scanner = NULL;
}
[super dealloc];
}
- (BOOL) enableCache
{
assert(0); // FIXME
return(NO);
}
- (void) setEnableCache: (BOOL) enable
{
zbar_image_scanner_enable_cache(scanner, enable);
}
- (ZBarSymbolSet*) results
{
const zbar_symbol_set_t *set = zbar_image_scanner_get_results(scanner);
return([[[ZBarSymbolSet alloc] initWithSymbolSet: set] autorelease]);
}
// image scanner config wrappers
- (void) parseConfig: (NSString*) cfg
{
zbar_image_scanner_parse_config(scanner, [cfg UTF8String]);
// FIXME throw errors
}
- (void) setSymbology: (zbar_symbol_type_t) sym
config: (zbar_config_t) cfg
to: (int) val
{
zbar_image_scanner_set_config(scanner, sym, cfg, val);
// FIXME throw errors
}
- (NSInteger) scanImage: (ZBarImage*) image
{
return(zbar_scan_image(scanner, image.zbarImage));
}
@end

View File

@ -0,0 +1,747 @@
//------------------------------------------------------------------------
// Copyright 2009-2010 (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
//------------------------------------------------------------------------
#import <ZBarSDK/ZBarReaderController.h>
#import <ZBarSDK/ZBarHelpController.h>
#import "debug.h"
/* the use of UIGetScreenImage() may no longer be sanctioned, even
* though it was previously "allowed". define this to 0 to rip it out
* and fall back to cameraMode=Default (manual capture)
*/
#ifndef USE_PRIVATE_APIS
# define USE_PRIVATE_APIS 0
#endif
#ifndef MIN_QUALITY
# define MIN_QUALITY 10
#endif
NSString* const ZBarReaderControllerResults = @"ZBarReaderControllerResults";
#if USE_PRIVATE_APIS
// expose undocumented API
CF_RETURNS_RETAINED
CGImageRef UIGetScreenImage(void);
#endif
@implementation ZBarReaderController
@synthesize scanner, readerDelegate, cameraMode, scanCrop, maxScanDimension,
showsHelpOnFail, takesPicture, enableCache, tracksSymbols;
@dynamic showsZBarControls;
- (id) init
{
if(self = [super init]) {
showsHelpOnFail = YES;
hasOverlay = showsZBarControls =
[self respondsToSelector: @selector(cameraOverlayView)];
enableCache = tracksSymbols = YES;
scanCrop = CGRectMake(0, 0, 1, 1);
maxScanDimension = 640;
scanner = [ZBarImageScanner new];
[scanner setSymbology: 0
config: ZBAR_CFG_X_DENSITY
to: 2];
[scanner setSymbology: 0
config: ZBAR_CFG_Y_DENSITY
to: 2];
if([UIImagePickerController
isSourceTypeAvailable: UIImagePickerControllerSourceTypeCamera])
self.sourceType = UIImagePickerControllerSourceTypeCamera;
#if USE_PRIVATE_APIS
cameraMode = ZBarReaderControllerCameraModeSampling;
#else
cameraMode = ZBarReaderControllerCameraModeDefault;
#endif
}
return(self);
}
- (void) initOverlay
{
CGRect bounds = self.view.bounds;
overlay = [[UIView alloc] initWithFrame: bounds];
overlay.backgroundColor = [UIColor clearColor];
CGRect r = bounds;
r.size.height -= 54;
boxView = [[UIView alloc] initWithFrame: r];
boxLayer = [CALayer new];
boxLayer.frame = r;
boxLayer.borderWidth = 1;
boxLayer.borderColor = [UIColor greenColor].CGColor;
[boxView.layer addSublayer: boxLayer];
toolbar = [UIToolbar new];
toolbar.barStyle = UIBarStyleBlackOpaque;
r.origin.y = r.size.height;
r.size.height = 54;
toolbar.frame = r;
cancelBtn = [[UIBarButtonItem alloc]
initWithBarButtonSystemItem: UIBarButtonSystemItemCancel
target: self
action: @selector(cancel)];
cancelBtn.width = r.size.width / 4 - 16;
scanBtn = [[UIBarButtonItem alloc]
initWithTitle: @"Scan!"
style: UIBarButtonItemStyleDone
target: self
action: @selector(scan)];
scanBtn.width = r.size.width / 2 - 16;
for(int i = 0; i < 2; i++)
space[i] = [[UIBarButtonItem alloc]
initWithBarButtonSystemItem:
UIBarButtonSystemItemFlexibleSpace
target: nil
action: nil];
space[2] = [[UIBarButtonItem alloc]
initWithBarButtonSystemItem:
UIBarButtonSystemItemFixedSpace
target: nil
action: nil];
space[2].width = r.size.width / 4 - 16;
infoBtn = [[UIButton buttonWithType: UIButtonTypeInfoLight] retain];
r.origin.x = r.size.width - 54;
r.size.width = 54;
infoBtn.frame = r;
[infoBtn addTarget: self
action: @selector(info)
forControlEvents: UIControlEventTouchUpInside];
}
- (void) viewDidLoad
{
[super viewDidLoad];
[super setDelegate: self];
if(hasOverlay)
[self initOverlay];
}
- (void) cleanup
{
[overlay release];
overlay = nil;
[boxView release];
boxView = nil;
[boxLayer release];
boxLayer = nil;
[toolbar release];
toolbar = nil;
[cancelBtn release];
cancelBtn = nil;
[scanBtn release];
scanBtn = nil;
for(int i = 0; i < 3; i++) {
[space[i] release];
space[i] = nil;
}
[infoBtn release];
infoBtn = nil;
[help release];
help = nil;
}
- (void) viewDidUnload
{
[self cleanup];
[super viewDidUnload];
}
- (void) dealloc
{
[self cleanup];
[scanner release];
scanner = nil;
[super dealloc];
}
- (void) scan
{
scanBtn.enabled = NO;
self.view.userInteractionEnabled = NO;
[self takePicture];
}
- (void) cancel
{
[self performSelector: @selector(imagePickerControllerDidCancel:)
withObject: self
afterDelay: 0.1];
}
- (void) reenable
{
scanBtn.enabled = YES;
self.view.userInteractionEnabled = YES;
}
- (void) initScanning
{
if(hasOverlay &&
self.sourceType == UIImagePickerControllerSourceTypeCamera) {
if(showsZBarControls || ![self cameraOverlayView])
[self setCameraOverlayView: overlay];
UIView *activeOverlay = [self cameraOverlayView];
if(showsZBarControls) {
if(!toolbar.superview) {
[overlay addSubview: toolbar];
[overlay addSubview: infoBtn];
}
[self setShowsCameraControls: NO];
}
else {
[toolbar removeFromSuperview];
[infoBtn removeFromSuperview];
if(activeOverlay == overlay)
[self setShowsCameraControls: YES];
}
self.view.userInteractionEnabled = YES;
sampling = (cameraMode == ZBarReaderControllerCameraModeSampling ||
cameraMode == ZBarReaderControllerCameraModeSequence);
if(sampling) {
toolbar.items = [NSArray arrayWithObjects:
cancelBtn, space[0], nil];
t_frame = timer_now();
dt_frame = 0;
boxLayer.opacity = 0;
if(boxView.superview != activeOverlay)
[boxView removeFromSuperview];
if(!boxView.superview)
[activeOverlay insertSubview: boxView atIndex:0];
scanner.enableCache = enableCache;
SEL meth = nil;
if(cameraMode == ZBarReaderControllerCameraModeSampling) {
// ensure crop rect does not include controls
if(scanCrop.origin.x + scanCrop.size.width > .8875)
scanCrop.size.width = .8875 - scanCrop.origin.x;
meth = @selector(scanScreen);
}
else
meth = @selector(takePicture);
[self performSelector: meth
withObject: nil
afterDelay: 2];
#ifdef DEBUG_OBJC
[self performSelector: @selector(dumpFPS)
withObject: nil
afterDelay: 4];
#endif
}
else {
scanBtn.enabled = NO;
toolbar.items = [NSArray arrayWithObjects:
cancelBtn, space[0], scanBtn, space[1], space[2], nil];
[self performSelector: @selector(reenable)
withObject: nil
afterDelay: .5];
[boxView removeFromSuperview];
}
}
}
- (void) viewWillAppear: (BOOL) animated
{
[self initScanning];
[super viewWillAppear: animated];
}
- (void) viewWillDisappear: (BOOL) animated
{
sampling = NO;
scanner.enableCache = NO;
[super viewWillDisappear: animated];
}
- (BOOL) showsZBarControls
{
return(showsZBarControls);
}
- (void) setCameraMode: (ZBarReaderControllerCameraMode) mode
{
#if !USE_PRIVATE_APIS
if(mode == ZBarReaderControllerCameraModeSampling)
[NSException raise: NSInvalidArgumentException
format: @"ZBarReaderController cannot set cameraMode=Sampling"
@" when USE_PRIVATE_APIS=0"];
#endif
cameraMode = mode;
}
- (void) setShowsZBarControls: (BOOL) show
{
if(show && !hasOverlay)
[NSException raise: NSInvalidArgumentException
format: @"ZBarReaderController cannot set showsZBarControls=YES for OS<3.1"];
showsZBarControls = show;
}
// intercept delegate as readerDelegate
- (void) setDelegate: (id <UINavigationControllerDelegate,
UIImagePickerControllerDelegate>) delegate
{
self.readerDelegate = (id <ZBarReaderDelegate>)delegate;
}
#ifdef DEBUG_OBJC
- (void) dumpFPS
{
if(!sampling)
return;
[self performSelector: @selector(dumpFPS)
withObject: nil
afterDelay: 2];
zlog(@"fps=%g", 1 / dt_frame);
}
#endif
- (NSInteger) scanImage: (CGImageRef) image
withScaling: (CGFloat) scale
{
uint64_t now = timer_now();
if(dt_frame)
dt_frame = (dt_frame + timer_elapsed(t_frame, now)) / 2;
else
dt_frame = timer_elapsed(t_frame, now);
t_frame = now;
int w = CGImageGetWidth(image);
int h = CGImageGetHeight(image);
CGRect crop;
if(w >= h)
crop = CGRectMake(scanCrop.origin.x * w, scanCrop.origin.y * h,
scanCrop.size.width * w, scanCrop.size.height * h);
else
crop = CGRectMake(scanCrop.origin.y * w, scanCrop.origin.x * h,
scanCrop.size.height * w, scanCrop.size.width * h);
CGSize size;
if(crop.size.width >= crop.size.height &&
crop.size.width > maxScanDimension)
size = CGSizeMake(maxScanDimension,
crop.size.height * maxScanDimension / crop.size.width);
else if(crop.size.height > maxScanDimension)
size = CGSizeMake(crop.size.width * maxScanDimension / crop.size.height,
maxScanDimension);
else
size = crop.size;
if(scale) {
size.width *= scale;
size.height *= scale;
}
if(self.sourceType != UIImagePickerControllerSourceTypeCamera ||
cameraMode == ZBarReaderControllerCameraModeDefault) {
// limit the maximum number of scan passes
int density;
if(size.width > 720)
density = (size.width / 240 + 1) / 2;
else
density = 1;
[scanner setSymbology: 0
config: ZBAR_CFG_X_DENSITY
to: density];
if(size.height > 720)
density = (size.height / 240 + 1) / 2;
else
density = 1;
[scanner setSymbology: 0
config: ZBAR_CFG_Y_DENSITY
to: density];
}
ZBarImage *zimg = [[ZBarImage alloc]
initWithCGImage: image
crop: crop
size: size];
int nsyms = [scanner scanImage: zimg];
[zimg release];
return(nsyms);
}
- (ZBarSymbol*) extractBestResult: (BOOL) filter
{
ZBarSymbol *sym = nil;
ZBarSymbolSet *results = scanner.results;
results.filterSymbols = filter;
for(ZBarSymbol *s in results)
if(!sym || sym.quality < s.quality)
sym = s;
return(sym);
}
- (void) updateBox: (ZBarSymbol*) sym
imageSize: (CGSize) size
{
[CATransaction begin];
[CATransaction setAnimationDuration: .3];
[CATransaction setAnimationTimingFunction:
[CAMediaTimingFunction functionWithName:
kCAMediaTimingFunctionLinear]];
CGFloat alpha = boxLayer.opacity;
if(sym) {
CGRect r = sym.bounds;
if(r.size.width > 16 && r.size.height > 16) {
r.origin.x += scanCrop.origin.y * size.width;
r.origin.y += scanCrop.origin.x * size.height;
r = CGRectInset(r, -16, -16);
if(alpha > .25) {
CGRect frame = boxLayer.frame;
r.origin.x = (r.origin.x * 3 + frame.origin.x) / 4;
r.origin.y = (r.origin.y * 3 + frame.origin.y) / 4;
r.size.width = (r.size.width * 3 + frame.size.width) / 4;
r.size.height = (r.size.height * 3 + frame.size.height) / 4;
}
boxLayer.frame = r;
boxLayer.opacity = 1;
}
}
else {
if(alpha > .1)
boxLayer.opacity = alpha / 2;
else if(alpha)
boxLayer.opacity = 0;
}
[CATransaction commit];
}
#if USE_PRIVATE_APIS
- (void) scanScreen
{
if(!sampling)
return;
// FIXME ugly hack: use private API to sample screen
CGImageRef image = UIGetScreenImage();
[self scanImage: image
withScaling: 0];
CGSize size = CGSizeMake(CGImageGetWidth(image), CGImageGetHeight(image));
CGImageRelease(image);
ZBarSymbol *sym = [self extractBestResult: NO];
if(sym && !sym.count) {
SEL cb = @selector(imagePickerController:didFinishPickingMediaWithInfo:);
if(takesPicture) {
symbol = [sym retain];
[self takePicture];
}
else if([readerDelegate respondsToSelector: cb]) {
symbol = [sym retain];
[CATransaction begin];
[CATransaction setDisableActions: YES];
boxLayer.opacity = 0;
[CATransaction commit];
// capture preview image and send to delegate
// after box has been hidden
[self performSelector: @selector(captureScreen)
withObject: nil
afterDelay: 0.001];
return;
}
}
// reschedule
[self performSelector: @selector(scanScreen)
withObject: nil
afterDelay: 0.001];
if(tracksSymbols)
[self updateBox: sym
imageSize: size];
}
- (void) captureScreen
{
CGImageRef screen = UIGetScreenImage();
CGRect r = CGRectMake(0, 0,
CGImageGetWidth(screen), CGImageGetHeight(screen));
if(r.size.width > r.size.height)
r.size.width -= 54;
else
r.size.height -= 54;
CGImageRef preview = CGImageCreateWithImageInRect(screen, r);
CGImageRelease(screen);
UIImage *image = [UIImage imageWithCGImage: preview];
CGImageRelease(preview);
[readerDelegate
imagePickerController: self
didFinishPickingMediaWithInfo:
[NSDictionary dictionaryWithObjectsAndKeys:
image, UIImagePickerControllerOriginalImage,
[NSArray arrayWithObject: symbol],
ZBarReaderControllerResults,
nil]];
[symbol release];
symbol = nil;
// continue scanning until dismissed
[self performSelector: @selector(scanScreen)
withObject: nil
afterDelay: 0.001];
}
#endif /* USE_PRIVATE_APIS */
- (void) scanSequence: (UIImage*) image
{
if(!sampling) {
[image release];
return;
}
int nsyms = [self scanImage: image.CGImage
withScaling: 0];
ZBarSymbol *sym = nil;
if(nsyms)
[self extractBestResult: NO];
SEL cb = @selector(imagePickerController:didFinishPickingMediaWithInfo:);
if(sym && !sym.count &&
[readerDelegate respondsToSelector: cb])
[readerDelegate
imagePickerController: self
didFinishPickingMediaWithInfo:
[NSDictionary dictionaryWithObjectsAndKeys:
image, UIImagePickerControllerOriginalImage,
[NSArray arrayWithObject: sym],
ZBarReaderControllerResults,
nil]];
CGSize size = image.size;
[image release];
// reschedule
[self performSelector: @selector(takePicture)
withObject: nil
afterDelay: 0.001];
if(tracksSymbols)
[self updateBox: sym
imageSize: size];
}
- (void) showHelpWithReason: (NSString*) reason
{
if(help) {
[help.view removeFromSuperview];
[help release];
}
help = [[ZBarHelpController alloc]
initWithReason: reason];
help.delegate = (id<ZBarHelpDelegate>)self;
if(self.sourceType != UIImagePickerControllerSourceTypeCamera) {
[self presentModalViewController: help
animated: YES];
return;
}
// show help as overlay view to workaround controller bugs
sampling = NO;
scanner.enableCache = NO;
help.wantsFullScreenLayout = YES;
help.view.alpha = 0;
UIView *activeOverlay = [self cameraOverlayView];
help.view.frame = [activeOverlay
convertRect: CGRectMake(0, 0, 320, 480)
fromView: nil];
[activeOverlay addSubview: help.view];
[UIView beginAnimations: @"ZBarHelp"
context: nil];
help.view.alpha = 1;
[UIView commitAnimations];
}
- (void) info
{
[self showHelpWithReason: @"INFO"];
}
- (void) imagePickerController: (UIImagePickerController*) picker
didFinishPickingMediaWithInfo: (NSDictionary*) info
{
UIImage *img = [info objectForKey: UIImagePickerControllerOriginalImage];
id results = nil;
if(self.sourceType == UIImagePickerControllerSourceTypeCamera &&
cameraMode == ZBarReaderControllerCameraModeSequence) {
if(sampling)
[self performSelector: @selector(scanSequence:)
withObject: [img retain]
afterDelay: 0.001];
return;
}
else if(!sampling)
results = [self scanImage: img.CGImage];
else {
results = [NSArray arrayWithObject: symbol];
[symbol release];
symbol = nil;
}
[self performSelector: @selector(reenable)
withObject: nil
afterDelay: .25];
if(results) {
NSMutableDictionary *newinfo = [info mutableCopy];
[newinfo setObject: results
forKey: ZBarReaderControllerResults];
SEL cb = @selector(imagePickerController:didFinishPickingMediaWithInfo:);
if([readerDelegate respondsToSelector: cb])
[readerDelegate imagePickerController: self
didFinishPickingMediaWithInfo: newinfo];
else
[self dismissModalViewControllerAnimated: YES];
[newinfo release];
return;
}
BOOL camera = (self.sourceType == UIImagePickerControllerSourceTypeCamera);
BOOL retry = !camera || (hasOverlay && ![self showsCameraControls]);
if(showsHelpOnFail && retry)
[self showHelpWithReason: @"FAIL"];
SEL cb = @selector(readerControllerDidFailToRead:withRetry:);
if([readerDelegate respondsToSelector: cb])
// assume delegate dismisses controller if necessary
[readerDelegate readerControllerDidFailToRead: self
withRetry: retry];
else if(!retry)
// must dismiss stock controller
[self dismissModalViewControllerAnimated: YES];
}
- (void) imagePickerControllerDidCancel: (UIImagePickerController*) picker
{
SEL cb = @selector(imagePickerControllerDidCancel:);
if([readerDelegate respondsToSelector: cb])
[readerDelegate imagePickerControllerDidCancel: self];
else
[self dismissModalViewControllerAnimated: YES];
}
// ZBarHelpDelegate
- (void) helpControllerDidFinish: (ZBarHelpController*) hlp
{
if(self.sourceType == UIImagePickerControllerSourceTypeCamera) {
[UIView beginAnimations: @"ZBarHelp"
context: nil];
hlp.view.alpha = 0;
[UIView commitAnimations];
[self initScanning];
}
else
[hlp dismissModalViewControllerAnimated: YES];
}
- (id <NSFastEnumeration>) scanImage: (CGImageRef) image
{
timer_start;
int nsyms = [self scanImage: image
withScaling: 0];
if(!nsyms &&
CGImageGetWidth(image) >= 640 &&
CGImageGetHeight(image) >= 640)
// make one more attempt for close up, grainy images
nsyms = [self scanImage: image
withScaling: .5];
NSMutableArray *syms = nil;
if(nsyms) {
// quality/type filtering
int max_quality = MIN_QUALITY;
for(ZBarSymbol *sym in scanner.results) {
zbar_symbol_type_t type = sym.type;
int quality;
if(type == ZBAR_QRCODE)
quality = INT_MAX;
else
quality = sym.quality;
if(quality < max_quality) {
zlog(@" type=%d quality=%d < %d\n",
type, quality, max_quality);
continue;
}
if(max_quality < quality) {
max_quality = quality;
if(syms)
[syms removeAllObjects];
}
zlog(@" type=%d quality=%d\n", type, quality);
if(!syms)
syms = [NSMutableArray arrayWithCapacity: 1];
[syms addObject: sym];
}
}
zlog(@"read %d filtered symbols in %gs total\n",
(!syms) ? 0 : [syms count], timer_elapsed(t_start, timer_now()));
return(syms);
}
@end

596
iphone/ZBarReaderView.m Normal file
View File

@ -0,0 +1,596 @@
//------------------------------------------------------------------------
// Copyright 2010 (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
//------------------------------------------------------------------------
#import <ZBarSDK/ZBarReaderView.h>
#define MODULE ZBarReaderView
#import "debug.h"
// silence warning
@interface ZBarReaderViewImpl : NSObject
@end
@implementation ZBarReaderView
@synthesize readerDelegate, tracksSymbols, trackingColor, torchMode, showsFPS,
zoom, maxZoom, scanCrop, previewTransform, captureReader;
@dynamic scanner, allowsPinchZoom, enableCache, device, session;
+ (id) alloc
{
if(self == [ZBarReaderView class]) {
// this is an abstract wrapper for implementation selected
// at compile time. replace with concrete subclass.
return((id)[ZBarReaderViewImpl alloc]);
}
return([super alloc]);
}
- (void) initSubviews
{
assert(preview);
overlay = [CALayer new];
overlay.backgroundColor = [UIColor clearColor].CGColor;
[preview addSublayer: overlay];
#ifndef NDEBUG
overlay.borderWidth = 2;
overlay.borderColor = [UIColor colorWithRed: 1
green: 0
blue: 0
alpha: .5].CGColor;
cropLayer = [CALayer new];
cropLayer.backgroundColor = [UIColor clearColor].CGColor;
cropLayer.borderWidth = 2;
cropLayer.borderColor = [UIColor colorWithRed: 0
green: 0
blue: 1
alpha: .5].CGColor;
[overlay addSublayer: cropLayer];
#endif
tracking = [CALayer new];
tracking.opacity = 0;
tracking.borderWidth = 1;
tracking.backgroundColor = [UIColor clearColor].CGColor;
[overlay addSublayer: tracking];
trackingColor = [[UIColor greenColor]
retain];
tracking.borderColor = trackingColor.CGColor;
fpsView = [UIView new];
fpsView.backgroundColor = [UIColor colorWithWhite: 0
alpha: .333];
fpsView.layer.cornerRadius = 12;
fpsView.hidden = YES;
[self addSubview: fpsView];
fpsLabel = [[UILabel alloc]
initWithFrame: CGRectMake(0, 0, 80, 32)];
fpsLabel.backgroundColor = [UIColor clearColor];
fpsLabel.textColor = [UIColor colorWithRed: .333
green: .666
blue: 1
alpha: 1];
fpsLabel.font = [UIFont systemFontOfSize: 18];
fpsLabel.textAlignment = UITextAlignmentRight;
[fpsView addSubview: fpsLabel];
self.zoom = 1.25;
}
- (void) _initWithImageScanner: (ZBarImageScanner*) scanner
{
assert(scanner);
tracksSymbols = YES;
interfaceOrientation = UIInterfaceOrientationPortrait;
torchMode = 2; // AVCaptureTorchModeAuto
scanCrop = effectiveCrop = CGRectMake(0, 0, 1, 1);
imageScale = 1;
previewTransform = CGAffineTransformIdentity;
maxZoom = 2;
pinch = [[UIPinchGestureRecognizer alloc]
initWithTarget: self
action: @selector(handlePinch)];
[self addGestureRecognizer: pinch];
}
- (id) initWithImageScanner: (ZBarImageScanner*) scanner
{
self = [super initWithFrame: CGRectMake(0, 0, 320, 426)];
if(!self)
return(nil);
self.backgroundColor = [UIColor blackColor];
self.contentMode = UIViewContentModeScaleAspectFill;
self.clipsToBounds = YES;
self.autoresizingMask =
UIViewAutoresizingFlexibleWidth |
UIViewAutoresizingFlexibleHeight;
[self _initWithImageScanner: scanner];
return(self);
}
- (id) init
{
ZBarImageScanner *scanner =
[[ZBarImageScanner new]
autorelease];
self = [self initWithImageScanner: scanner];
if(!self)
return(nil);
[scanner setSymbology: 0
config: ZBAR_CFG_X_DENSITY
to: 3];
[scanner setSymbology: 0
config: ZBAR_CFG_Y_DENSITY
to: 3];
return(self);
}
- (id) initWithCoder: (NSCoder*) decoder
{
self = [super initWithCoder: decoder];
if(!self)
return(nil);
ZBarImageScanner *scanner =
[[ZBarImageScanner new]
autorelease];
[self _initWithImageScanner: scanner];
[scanner setSymbology: 0
config: ZBAR_CFG_X_DENSITY
to: 3];
[scanner setSymbology: 0
config: ZBAR_CFG_Y_DENSITY
to: 3];
return(self);
}
- (void) dealloc
{
[preview removeFromSuperlayer];
[preview release];
preview = nil;
[overlay release];
overlay = nil;
[cropLayer release];
cropLayer = nil;
[tracking release];
tracking = nil;
[trackingColor release];
trackingColor = nil;
[fpsLabel release];
fpsLabel = nil;
[fpsView release];
fpsView = nil;
[pinch release];
pinch = nil;
[super dealloc];
}
- (void) resetTracking
{
[tracking removeAllAnimations];
[CATransaction begin];
[CATransaction setDisableActions: YES];
CGSize size = overlay.bounds.size;
CGRect crop = effectiveCrop;
tracking.frame = CGRectMake(crop.origin.x * size.width,
crop.origin.y * size.height,
crop.size.width * size.width,
crop.size.height * size.height);
tracking.opacity = 0;
[CATransaction commit];
}
- (void) updateCrop
{
}
static inline CGFloat rotationForInterfaceOrientation (int orient)
{
// resolve camera/device image orientation to view/interface orientation
switch(orient)
{
case UIInterfaceOrientationLandscapeLeft:
return(M_PI_2);
case UIInterfaceOrientationPortraitUpsideDown:
return(M_PI);
case UIInterfaceOrientationLandscapeRight:
return(3 * M_PI_2);
case UIInterfaceOrientationPortrait:
return(2 * M_PI);
}
return(0);
}
- (void) layoutSubviews
{
CGRect bounds = self.bounds;
if(!bounds.size.width || !bounds.size.height)
return;
[CATransaction begin];
if(animationDuration) {
[CATransaction setAnimationDuration: animationDuration];
[CATransaction setAnimationTimingFunction:
[CAMediaTimingFunction functionWithName:
kCAMediaTimingFunctionEaseInEaseOut]];
}
else
[CATransaction setDisableActions: YES];
[super layoutSubviews];
fpsView.frame = CGRectMake(bounds.size.width - 80, bounds.size.height - 32,
80 + 12, 32 + 12);
// orient view bounds to match camera image
CGSize psize;
if(UIInterfaceOrientationIsPortrait(interfaceOrientation))
psize = CGSizeMake(bounds.size.height, bounds.size.width);
else
psize = bounds.size;
// calculate scale from view coordinates to image coordinates
// FIXME assumes AVLayerVideoGravityResizeAspectFill
CGFloat scalex = imageSize.width / psize.width;
CGFloat scaley = imageSize.height / psize.height;
imageScale = (scalex < scaley) ? scalex : scaley;
if(!imageScale)
imageScale = 1;
// apply zoom
imageScale /= zoom;
// scale crop by zoom factor
CGFloat z = 1 / zoom;
CGFloat t = (1 - z) / 2;
CGRect zoomCrop =
CGRectMake(scanCrop.origin.x * z + t,
scanCrop.origin.y * z + t,
scanCrop.size.width * z,
scanCrop.size.height * z);
// convert effective preview area to normalized image coordinates
CGRect previewCrop;
if(scalex < scaley && imageSize.height)
previewCrop.size =
CGSizeMake(z, psize.height * imageScale / imageSize.height);
else if(imageSize.width)
previewCrop.size =
CGSizeMake(psize.width * imageScale / imageSize.width, z);
else
previewCrop.size = CGSizeMake(1, 1);
previewCrop.origin = CGPointMake((1 - previewCrop.size.width) / 2,
(1 - previewCrop.size.height) / 2);
// clip crop to visible preview area
effectiveCrop = CGRectIntersection(zoomCrop, previewCrop);
if(CGRectIsNull(effectiveCrop))
effectiveCrop = zoomCrop;
// size preview to match image in view coordinates
CGFloat viewScale = 1 / imageScale;
if(imageSize.width && imageSize.height)
psize = CGSizeMake(imageSize.width * viewScale,
imageSize.height * viewScale);
preview.bounds = CGRectMake(0, 0, psize.height, psize.width);
// center preview in view
preview.position = CGPointMake(bounds.size.width / 2,
bounds.size.height / 2);
CGFloat angle = rotationForInterfaceOrientation(interfaceOrientation);
CATransform3D xform =
CATransform3DMakeAffineTransform(previewTransform);
preview.transform = CATransform3DRotate(xform, angle, 0, 0, 1);
// scale overlay to match actual image
if(imageSize.width && imageSize.height)
overlay.bounds = CGRectMake(0, 0, imageSize.width, imageSize.height);
else
overlay.bounds = CGRectMake(0, 0, psize.width, psize.height);
// center overlay in preview
overlay.position = CGPointMake(psize.height / 2, psize.width / 2);
// image coordinates rotated from preview
xform = CATransform3DMakeRotation(M_PI_2, 0, 0, 1);
overlay.transform = CATransform3DScale(xform, viewScale, viewScale, 1);
tracking.borderWidth = imageScale;
#ifndef NDEBUG
preview.backgroundColor = [UIColor yellowColor].CGColor;
overlay.borderWidth = 2 * imageScale;
cropLayer.borderWidth = 2 * imageScale;
cropLayer.frame = CGRectMake(effectiveCrop.origin.x * imageSize.width,
effectiveCrop.origin.y * imageSize.height,
effectiveCrop.size.width * imageSize.width,
effectiveCrop.size.height * imageSize.height);
zlog(@"layoutSubviews: bounds=%@ orient=%d image=%@ crop=%@ zoom=%g\n"
@"=> preview=%@ crop=(z%@ p%@ %@ i%@) scale=%g %c %g = 1/%g",
NSStringFromCGSize(bounds.size), interfaceOrientation,
NSStringFromCGSize(imageSize), NSStringFromCGRect(scanCrop), zoom,
NSStringFromCGSize(psize), NSStringFromCGRect(zoomCrop),
NSStringFromCGRect(previewCrop), NSStringFromCGRect(effectiveCrop),
NSStringFromCGRect(cropLayer.frame),
scalex, (scalex > scaley) ? '>' : '<', scaley, viewScale);
#endif
[self resetTracking];
[self updateCrop];
[CATransaction commit];
animationDuration = 0;
}
- (void) setImageSize: (CGSize) size
{
zlog(@"imageSize=%@", NSStringFromCGSize(size));
imageSize = size;
// FIXME bug in AVCaptureVideoPreviewLayer fails to update preview location
preview.bounds = CGRectMake(0, 0, size.width, size.height);
[self setNeedsLayout];
}
- (void) willRotateToInterfaceOrientation: (UIInterfaceOrientation) orient
duration: (NSTimeInterval) duration
{
if(interfaceOrientation != orient) {
zlog(@"orient=%d #%g", orient, duration);
interfaceOrientation = orient;
animationDuration = duration;
}
}
- (void) setScanCrop: (CGRect) r
{
if(CGRectEqualToRect(scanCrop, r))
return;
scanCrop = r;
[self setNeedsLayout];
}
- (void) setTracksSymbols: (BOOL) track
{
if(track == tracksSymbols)
return;
tracksSymbols = track;
[self resetTracking];
}
- (BOOL) allowsPinchZoom
{
return(pinch.enabled);
}
- (void) setAllowsPinchZoom: (BOOL) enabled
{
pinch.enabled = enabled;
}
- (void) setTrackingColor: (UIColor*) color
{
if(!color)
return;
[color retain];
[trackingColor release];
trackingColor = color;
tracking.borderColor = color.CGColor;
}
- (void) setShowsFPS: (BOOL) show
{
if(show == showsFPS)
return;
fpsView.hidden = !show;
}
- (void) setZoom: (CGFloat) z
{
if(z < 1.0)
z = 1.0;
if(z > maxZoom)
z = maxZoom;
if(z == zoom)
return;
zoom = z;
[self setNeedsLayout];
}
- (void) setZoom: (CGFloat) z
animated: (BOOL) animated
{
[CATransaction begin];
if(animated) {
[CATransaction setAnimationDuration: .1];
[CATransaction setAnimationTimingFunction:
[CAMediaTimingFunction functionWithName:
kCAMediaTimingFunctionLinear]];
}
else
[CATransaction setDisableActions: YES];
// FIXME animate from current value
self.zoom = z;
[self layoutIfNeeded];
[CATransaction commit];
}
- (void) setPreviewTransform: (CGAffineTransform) xfrm
{
previewTransform = xfrm;
[self setNeedsLayout];
}
- (void) start
{
if(started)
return;
started = YES;
[self resetTracking];
fpsLabel.text = @"--- fps ";
[[UIDevice currentDevice]
beginGeneratingDeviceOrientationNotifications];
}
- (void) stop
{
if(!started)
return;
started = NO;
[[UIDevice currentDevice]
endGeneratingDeviceOrientationNotifications];
}
- (void) flushCache
{
}
// UIGestureRecognizer callback
- (void) handlePinch
{
if(pinch.state == UIGestureRecognizerStateBegan)
zoom0 = zoom;
CGFloat z = zoom0 * pinch.scale;
[self setZoom: z
animated: YES];
if((zoom < 1.5) != (z < 1.5)) {
int d = (z < 1.5) ? 3 : 2;
ZBarImageScanner *scanner = self.scanner;
@synchronized(scanner) {
[scanner setSymbology: 0
config: ZBAR_CFG_X_DENSITY
to: d];
[scanner setSymbology: 0
config: ZBAR_CFG_Y_DENSITY
to: d];
}
}
}
- (void) updateTracking: (CALayer*) trk
withSymbol: (ZBarSymbol*) sym
{
if(!sym)
return;
CGRect r = sym.bounds;
if(r.size.width <= 32 && r.size.height <= 32)
return;
r = CGRectInset(r, -24, -24);
CALayer *current = trk.presentationLayer;
CGPoint cp = current.position;
CGPoint p = CGPointMake(CGRectGetMidX(r), CGRectGetMidY(r));
p = CGPointMake((p.x * 3 + cp.x) / 4, (p.y * 3 + cp.y) / 4);
CGRect cr = current.bounds;
r.origin = cr.origin;
r.size.width = (r.size.width * 3 + cr.size.width) / 4;
r.size.height = (r.size.height * 3 + cr.size.height) / 4;
CAMediaTimingFunction *linear =
[CAMediaTimingFunction functionWithName: kCAMediaTimingFunctionLinear];
CABasicAnimation *resize =
[CABasicAnimation animationWithKeyPath: @"bounds"];
resize.fromValue = [NSValue valueWithCGRect: cr];
resize.toValue = [NSValue valueWithCGRect: r];
resize.duration = .2;
resize.timingFunction = linear;
resize.fillMode = kCAFillModeForwards;
resize.removedOnCompletion = NO;
CABasicAnimation *move =
[CABasicAnimation animationWithKeyPath: @"position"];
move.fromValue = [NSValue valueWithCGPoint: cp];
move.toValue = [NSValue valueWithCGPoint: p];
move.duration = .2;
move.timingFunction = linear;
move.fillMode = kCAFillModeForwards;
move.removedOnCompletion = NO;
CABasicAnimation *on =
[CABasicAnimation animationWithKeyPath: @"opacity"];
on.fromValue = [NSNumber numberWithDouble: current.opacity];
on.toValue = [NSNumber numberWithDouble: 1];
on.duration = .2;
on.timingFunction = linear;
on.fillMode = kCAFillModeForwards;
on.removedOnCompletion = NO;
CABasicAnimation *off = nil;
if(!TARGET_IPHONE_SIMULATOR) {
off = [CABasicAnimation animationWithKeyPath: @"opacity"];
off.fromValue = [NSNumber numberWithDouble: 1];
off.toValue = [NSNumber numberWithDouble: 0];
off.beginTime = .5;
off.duration = .5;
off.timingFunction = linear;
}
CAAnimationGroup *group = [CAAnimationGroup animation];
group.animations = [NSArray arrayWithObjects: resize, move, on, off, nil];
group.duration = 1;
group.fillMode = kCAFillModeForwards;
group.removedOnCompletion = !TARGET_IPHONE_SIMULATOR;
[trk addAnimation: group
forKey: @"tracking"];
}
- (void) didTrackSymbols: (ZBarSymbolSet*) syms
{
if(!tracksSymbols)
return;
int n = syms.count;
assert(n);
if(!n)
return;
ZBarSymbol *sym = nil;
for(ZBarSymbol *s in syms)
if(!sym || s.type == ZBAR_QRCODE || s.quality > sym.quality)
sym = s;
assert(sym);
if(!sym)
return;
[self updateTracking: tracking
withSymbol: sym];
}
@end

View File

@ -0,0 +1,699 @@
//------------------------------------------------------------------------
// Copyright 2010 (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
//------------------------------------------------------------------------
#import <ZBarSDK/ZBarReaderViewController.h>
#import <ZBarSDK/ZBarReaderView.h>
#import <ZBarSDK/ZBarCaptureReader.h>
#import <ZBarSDK/ZBarHelpController.h>
#import <ZBarSDK/ZBarCameraSimulator.h>
#define MODULE ZBarReaderViewController
#import "debug.h"
static inline AVCaptureDevicePosition
AVPositionForUICamera (UIImagePickerControllerCameraDevice camera)
{
switch(camera) {
case UIImagePickerControllerCameraDeviceRear:
return(AVCaptureDevicePositionBack);
case UIImagePickerControllerCameraDeviceFront:
return(AVCaptureDevicePositionFront);
}
return(-1);
}
static inline UIImagePickerControllerCameraDevice
UICameraForAVPosition (AVCaptureDevicePosition position)
{
switch(position)
{
case AVCaptureDevicePositionBack:
return(UIImagePickerControllerCameraDeviceRear);
case AVCaptureDevicePositionFront:
return(UIImagePickerControllerCameraDeviceFront);
}
return(-1);
}
static inline AVCaptureDevice*
AVDeviceForUICamera (UIImagePickerControllerCameraDevice camera)
{
AVCaptureDevicePosition position = AVPositionForUICamera(camera);
if(position < 0)
return(nil);
#if !TARGET_IPHONE_SIMULATOR
NSArray *allDevices =
[AVCaptureDevice devicesWithMediaType: AVMediaTypeVideo];
for(AVCaptureDevice *device in allDevices)
// FIXME how to quantify "best" of several (theoretical) possibilities
if(device.position == position)
return(device);
#endif
return(nil);
}
static inline AVCaptureTorchMode
AVTorchModeForUIFlashMode (UIImagePickerControllerCameraFlashMode mode)
{
switch(mode)
{
case UIImagePickerControllerCameraFlashModeAuto:
return(AVCaptureTorchModeAuto);
case UIImagePickerControllerCameraFlashModeOn:
return(AVCaptureTorchModeOn);
case UIImagePickerControllerCameraFlashModeOff:
break;
}
return(AVCaptureTorchModeOff);
}
static inline NSString*
AVSessionPresetForUIVideoQuality (UIImagePickerControllerQualityType quality)
{
#if !TARGET_IPHONE_SIMULATOR
switch(quality)
{
case UIImagePickerControllerQualityTypeHigh:
return(AVCaptureSessionPresetHigh);
case UIImagePickerControllerQualityType640x480:
return(AVCaptureSessionPreset640x480);
case UIImagePickerControllerQualityTypeMedium:
return(AVCaptureSessionPresetMedium);
case UIImagePickerControllerQualityTypeLow:
return(AVCaptureSessionPresetLow);
case UIImagePickerControllerQualityTypeIFrame1280x720:
return(AVCaptureSessionPresetiFrame1280x720);
case UIImagePickerControllerQualityTypeIFrame960x540:
return(AVCaptureSessionPresetiFrame960x540);
}
#endif
return(nil);
}
@implementation ZBarReaderViewController
@synthesize scanner, readerDelegate, showsZBarControls,
supportedOrientationsMask, tracksSymbols, enableCache, cameraOverlayView,
cameraViewTransform, cameraDevice, cameraFlashMode, videoQuality,
readerView, scanCrop;
@dynamic sourceType, allowsEditing, allowsImageEditing, showsCameraControls,
showsHelpOnFail, cameraMode, takesPicture, maxScanDimension;
+ (BOOL) isSourceTypeAvailable: (UIImagePickerControllerSourceType) sourceType
{
if(sourceType != UIImagePickerControllerSourceTypeCamera)
return(NO);
return(TARGET_IPHONE_SIMULATOR ||
[UIImagePickerController isSourceTypeAvailable: sourceType]);
}
+ (BOOL) isCameraDeviceAvailable: (UIImagePickerControllerCameraDevice) camera
{
return(TARGET_IPHONE_SIMULATOR ||
[UIImagePickerController isCameraDeviceAvailable: camera]);
}
+ (BOOL) isFlashAvailableForCameraDevice: (UIImagePickerControllerCameraDevice) camera
{
return(TARGET_IPHONE_SIMULATOR ||
[UIImagePickerController isFlashAvailableForCameraDevice: camera]);
}
+ (NSArray*) availableCaptureModesForCameraDevice: (UIImagePickerControllerCameraDevice) camera
{
if(![self isCameraDeviceAvailable: camera])
return([NSArray array]);
// current reader only supports automatic detection
return([NSArray arrayWithObject:
[NSNumber numberWithInteger:
UIImagePickerControllerCameraCaptureModeVideo]]);
}
- (void) _init
{
supportedOrientationsMask =
ZBarOrientationMask(UIInterfaceOrientationPortrait);
showsZBarControls = tracksSymbols = enableCache = YES;
scanCrop = CGRectMake(0, 0, 1, 1);
cameraViewTransform = CGAffineTransformIdentity;
cameraFlashMode = UIImagePickerControllerCameraFlashModeAuto;
videoQuality = UIImagePickerControllerQualityType640x480;
AVCaptureDevice *device = nil;
#if !TARGET_IPHONE_SIMULATOR
device = [AVCaptureDevice defaultDeviceWithMediaType: AVMediaTypeVideo];
#endif
if(device)
cameraDevice = UICameraForAVPosition(device.position);
else
cameraDevice = UIImagePickerControllerCameraDeviceRear;
// create our own scanner to store configuration,
// independent of whether view is loaded
scanner = [ZBarImageScanner new];
[scanner setSymbology: 0
config: ZBAR_CFG_X_DENSITY
to: 3];
[scanner setSymbology: 0
config: ZBAR_CFG_Y_DENSITY
to: 3];
}
- (id) init
{
if(!TARGET_IPHONE_SIMULATOR &&
!NSClassFromString(@"AVCaptureSession")) {
// fallback to old interface
zlog(@"Falling back to ZBarReaderController");
[self release];
return((id)[ZBarReaderController new]);
}
self = [super init];
if(!self)
return(nil);
self.wantsFullScreenLayout = YES;
[self _init];
return(self);
}
- (id) initWithCoder: (NSCoder*) decoder
{
self = [super initWithCoder: decoder];
if(!self)
return(nil);
[self _init];
return(self);
}
- (void) cleanup
{
[cameraOverlayView removeFromSuperview];
cameraSim.readerView = nil;
[cameraSim release];
cameraSim = nil;
readerView.readerDelegate = nil;
[readerView release];
readerView = nil;
[controls release];
controls = nil;
[shutter release];
shutter = nil;
}
- (void) dealloc
{
[self cleanup];
[cameraOverlayView release];
cameraOverlayView = nil;
[scanner release];
scanner = nil;
[super dealloc];
}
- (void) initControls
{
if(!showsZBarControls && controls) {
[controls removeFromSuperview];
[controls release];
controls = nil;
}
if(!showsZBarControls)
return;
UIView *view = self.view;
if(controls) {
assert(controls.superview == view);
[view bringSubviewToFront: controls];
return;
}
CGRect r = view.bounds;
r.origin.y = r.size.height - 54;
r.size.height = 54;
controls = [[UIView alloc]
initWithFrame: r];
controls.autoresizingMask =
UIViewAutoresizingFlexibleWidth |
UIViewAutoresizingFlexibleHeight |
UIViewAutoresizingFlexibleTopMargin;
controls.backgroundColor = [UIColor blackColor];
UIToolbar *toolbar =
[UIToolbar new];
r.origin.y = 0;
toolbar.frame = r;
toolbar.barStyle = UIBarStyleBlackOpaque;
toolbar.autoresizingMask =
UIViewAutoresizingFlexibleWidth |
UIViewAutoresizingFlexibleHeight;
UIButton *info =
[UIButton buttonWithType: UIButtonTypeInfoLight];
[info addTarget: self
action: @selector(info)
forControlEvents: UIControlEventTouchUpInside];
toolbar.items =
[NSArray arrayWithObjects:
[[[UIBarButtonItem alloc]
initWithBarButtonSystemItem: UIBarButtonSystemItemCancel
target: self
action: @selector(cancel)]
autorelease],
[[[UIBarButtonItem alloc]
initWithBarButtonSystemItem: UIBarButtonSystemItemFlexibleSpace
target: nil
action: nil]
autorelease],
[[[UIBarButtonItem alloc]
initWithCustomView: info]
autorelease],
nil];
[controls addSubview: toolbar];
[toolbar release];
[view addSubview: controls];
}
- (void) initVideoQuality
{
if(!readerView) {
assert(0);
return;
}
AVCaptureSession *session = readerView.session;
NSString *preset = AVSessionPresetForUIVideoQuality(videoQuality);
if(session && preset && [session canSetSessionPreset: preset]) {
zlog(@"set session preset=%@", preset);
session.sessionPreset = preset;
}
else
zlog(@"unable to set session preset=%@", preset);
}
- (void) loadView
{
self.view = [[UIView alloc]
initWithFrame: CGRectMake(0, 0, 320, 480)];
}
- (void) viewDidLoad
{
[super viewDidLoad];
UIView *view = self.view;
view.backgroundColor = [UIColor blackColor];
view.autoresizingMask =
UIViewAutoresizingFlexibleWidth |
UIViewAutoresizingFlexibleHeight;
readerView = [[ZBarReaderView alloc]
initWithImageScanner: scanner];
CGRect bounds = view.bounds;
CGRect r = bounds;
NSUInteger autoresize =
UIViewAutoresizingFlexibleWidth |
UIViewAutoresizingFlexibleHeight;
if(showsZBarControls ||
self.parentViewController.modalViewController == self)
{
autoresize |= UIViewAutoresizingFlexibleBottomMargin;
r.size.height -= 54;
}
readerView.frame = r;
readerView.autoresizingMask = autoresize;
AVCaptureDevice *device = AVDeviceForUICamera(cameraDevice);
if(device && device != readerView.device)
readerView.device = device;
readerView.torchMode = AVTorchModeForUIFlashMode(cameraFlashMode);
[self initVideoQuality];
readerView.readerDelegate = (id<ZBarReaderViewDelegate>)self;
readerView.scanCrop = scanCrop;
readerView.previewTransform = cameraViewTransform;
readerView.tracksSymbols = tracksSymbols;
readerView.enableCache = enableCache;
[view addSubview: readerView];
shutter = [[UIView alloc]
initWithFrame: r];
shutter.backgroundColor = [UIColor blackColor];
shutter.opaque = NO;
shutter.autoresizingMask =
UIViewAutoresizingFlexibleWidth |
UIViewAutoresizingFlexibleHeight;
[view addSubview: shutter];
if(cameraOverlayView) {
assert(!cameraOverlayView.superview);
[cameraOverlayView removeFromSuperview];
[view addSubview: cameraOverlayView];
}
[self initControls];
if(TARGET_IPHONE_SIMULATOR) {
cameraSim = [[ZBarCameraSimulator alloc]
initWithViewController: self];
cameraSim.readerView = readerView;
}
}
- (void) viewDidUnload
{
[cameraOverlayView removeFromSuperview];
[self cleanup];
[super viewDidUnload];
}
- (void) viewWillAppear: (BOOL) animated
{
zlog(@"willAppear: anim=%d orient=%d",
animated, self.interfaceOrientation);
[self initControls];
[super viewWillAppear: animated];
[readerView willRotateToInterfaceOrientation: self.interfaceOrientation
duration: 0];
[readerView performSelector: @selector(start)
withObject: nil
afterDelay: .001];
shutter.alpha = 1;
shutter.hidden = NO;
UIApplication *app = [UIApplication sharedApplication];
BOOL willHideStatusBar =
!didHideStatusBar && self.wantsFullScreenLayout && !app.statusBarHidden;
if(willHideStatusBar)
[app setStatusBarHidden: YES
withAnimation: UIStatusBarAnimationFade];
didHideStatusBar = didHideStatusBar || willHideStatusBar;
}
- (void) dismissModalViewControllerAnimated: (BOOL) animated
{
if(didHideStatusBar) {
[[UIApplication sharedApplication]
setStatusBarHidden: NO
withAnimation: UIStatusBarAnimationFade];
didHideStatusBar = NO;
}
[super dismissModalViewControllerAnimated: animated];
}
- (void) viewWillDisappear: (BOOL) animated
{
readerView.captureReader.enableReader = NO;
if(didHideStatusBar) {
[[UIApplication sharedApplication]
setStatusBarHidden: NO
withAnimation: UIStatusBarAnimationFade];
didHideStatusBar = NO;
}
[super viewWillDisappear: animated];
}
- (void) viewDidDisappear: (BOOL) animated
{
// stopRunning can take a really long time (>1s observed),
// so defer until the view transitions are complete
[readerView stop];
}
- (BOOL) shouldAutorotateToInterfaceOrientation: (UIInterfaceOrientation) orient
{
return((supportedOrientationsMask >> orient) & 1);
}
- (void) willRotateToInterfaceOrientation: (UIInterfaceOrientation) orient
duration: (NSTimeInterval) duration
{
zlog(@"willRotate: orient=%d #%g", orient, duration);
rotating = YES;
if(readerView)
[readerView willRotateToInterfaceOrientation: orient
duration: duration];
}
- (void) willAnimateRotationToInterfaceOrientation: (UIInterfaceOrientation) orient
duration: (NSTimeInterval) duration
{
zlog(@"willAnimateRotation: orient=%d #%g", orient, duration);
if(helpController)
[helpController willAnimateRotationToInterfaceOrientation: orient
duration: duration];
if(readerView)
[readerView setNeedsLayout];
}
- (void) didRotateFromInterfaceOrientation: (UIInterfaceOrientation) orient
{
zlog(@"didRotate(%d): orient=%d", rotating, orient);
if(!rotating && readerView) {
// work around UITabBarController bug: willRotate is not called
// for non-portrait initial interface orientation
[readerView willRotateToInterfaceOrientation: self.interfaceOrientation
duration: 0];
[readerView setNeedsLayout];
}
rotating = NO;
}
- (ZBarReaderView*) readerView
{
// force view to load
(void)self.view;
assert(readerView);
return(readerView);
}
- (void) setTracksSymbols: (BOOL) track
{
tracksSymbols = track;
if(readerView)
readerView.tracksSymbols = track;
}
- (void) setEnableCache: (BOOL) enable
{
enableCache = enable;
if(readerView)
readerView.enableCache = enable;
}
- (void) setScanCrop: (CGRect) r
{
scanCrop = r;
if(readerView)
readerView.scanCrop = r;
}
- (void) setCameraOverlayView: (UIView*) newview
{
UIView *oldview = cameraOverlayView;
[oldview removeFromSuperview];
cameraOverlayView = [newview retain];
if([self isViewLoaded] && newview)
[self.view addSubview: newview];
[oldview release];
}
- (void) setCameraViewTransform: (CGAffineTransform) xfrm
{
cameraViewTransform = xfrm;
if(readerView)
readerView.previewTransform = xfrm;
}
- (void) cancel
{
if(!readerDelegate)
return;
SEL cb = @selector(imagePickerControllerDidCancel:);
if([readerDelegate respondsToSelector: cb])
[readerDelegate
imagePickerControllerDidCancel: (UIImagePickerController*)self];
else
[self dismissModalViewControllerAnimated: YES];
}
- (void) info
{
[self showHelpWithReason: @"INFO"];
}
- (void) showHelpWithReason: (NSString*) reason
{
if(helpController)
return;
helpController = [[ZBarHelpController alloc]
initWithReason: reason];
helpController.delegate = (id<ZBarHelpDelegate>)self;
helpController.wantsFullScreenLayout = YES;
UIView *helpView = helpController.view;
helpView.alpha = 0;
helpView.frame = self.view.bounds;
[helpController viewWillAppear: YES];
[self.view addSubview: helpView];
[UIView beginAnimations: @"ZBarHelp"
context: nil];
helpController.view.alpha = 1;
[UIView commitAnimations];
}
- (void) takePicture
{
if(TARGET_IPHONE_SIMULATOR) {
[cameraSim takePicture];
// FIXME return selected image
}
else if(readerView)
[readerView.captureReader captureFrame];
}
- (void) setCameraDevice: (UIImagePickerControllerCameraDevice) camera
{
cameraDevice = camera;
if(readerView) {
AVCaptureDevice *device = AVDeviceForUICamera(camera);
if(device)
readerView.device = device;
}
}
- (void) setCameraFlashMode: (UIImagePickerControllerCameraFlashMode) mode
{
cameraFlashMode = mode;
if(readerView)
readerView.torchMode = AVTorchModeForUIFlashMode(mode);
}
- (UIImagePickerControllerCameraCaptureMode) cameraCaptureMode
{
return(UIImagePickerControllerCameraCaptureModeVideo);
}
- (void) setCameraCaptureMode: (UIImagePickerControllerCameraCaptureMode) mode
{
NSAssert2(mode == UIImagePickerControllerCameraCaptureModeVideo,
@"attempt to set unsupported value (%d)"
@" for %@ property", mode, @"cameraCaptureMode");
}
- (void) setVideoQuality: (UIImagePickerControllerQualityType) quality
{
videoQuality = quality;
if(readerView)
[self initVideoQuality];
}
// ZBarHelpDelegate
- (void) helpControllerDidFinish: (ZBarHelpController*) help
{
assert(help == helpController);
[help viewWillDisappear: YES];
[UIView beginAnimations: @"ZBarHelp"
context: NULL];
[UIView setAnimationDelegate: self];
[UIView setAnimationDidStopSelector: @selector(removeHelp:done:context:)];
help.view.alpha = 0;
[UIView commitAnimations];
}
- (void) removeHelp: (NSString*) tag
done: (NSNumber*) done
context: (void*) ctx
{
if([tag isEqualToString: @"ZBarHelp"] && helpController) {
[helpController.view removeFromSuperview];
[helpController release];
helpController = nil;
}
}
// ZBarReaderViewDelegate
- (void) readerView: (ZBarReaderView*) readerView
didReadSymbols: (ZBarSymbolSet*) syms
fromImage: (UIImage*) image
{
[readerDelegate
imagePickerController: (UIImagePickerController*)self
didFinishPickingMediaWithInfo:
[NSDictionary dictionaryWithObjectsAndKeys:
image, UIImagePickerControllerOriginalImage,
syms, ZBarReaderControllerResults,
nil]];
}
- (void) readerViewDidStart: (ZBarReaderView*) readerView
{
if(!shutter.hidden)
[UIView animateWithDuration: .25
animations: ^{
shutter.alpha = 0;
}
completion: ^(BOOL finished) {
shutter.hidden = YES;
}];
}
// "deprecated" properties
#define DEPRECATED_PROPERTY(getter, setter, type, val, ignore) \
- (type) getter \
{ \
return(val); \
} \
- (void) setter: (type) v \
{ \
NSAssert2(ignore || v == val, \
@"attempt to set unsupported value (%d)" \
@" for %@ property", val, @#getter); \
}
DEPRECATED_PROPERTY(sourceType, setSourceType, UIImagePickerControllerSourceType, UIImagePickerControllerSourceTypeCamera, NO)
DEPRECATED_PROPERTY(allowsEditing, setAllowsEditing, BOOL, NO, NO)
DEPRECATED_PROPERTY(allowsImageEditing, setAllowsImageEditing, BOOL, NO, NO)
DEPRECATED_PROPERTY(showsCameraControls, setShowsCameraControls, BOOL, NO, NO)
DEPRECATED_PROPERTY(showsHelpOnFail, setShowsHelpOnFail, BOOL, NO, YES)
DEPRECATED_PROPERTY(cameraMode, setCameraMode, ZBarReaderControllerCameraMode, ZBarReaderControllerCameraModeSampling, NO)
DEPRECATED_PROPERTY(takesPicture, setTakesPicture, BOOL, NO, NO)
DEPRECATED_PROPERTY(maxScanDimension, setMaxScanDimension, NSInteger, 640, YES)
@end

View File

@ -0,0 +1,402 @@
//------------------------------------------------------------------------
// Copyright 2010 (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
//------------------------------------------------------------------------
#import <AVFoundation/AVFoundation.h>
#import <CoreMedia/CoreMedia.h>
#import <CoreVideo/CoreVideo.h>
#import <ZBarSDK/ZBarReaderView.h>
#import <ZBarSDK/ZBarCaptureReader.h>
#define MODULE ZBarReaderView
#import "debug.h"
// protected APIs
@interface ZBarReaderView()
- (void) _initWithImageScanner: (ZBarImageScanner*) _scanner;
- (void) initSubviews;
- (void) updateCrop;
- (void) setImageSize: (CGSize) size;
- (void) didTrackSymbols: (ZBarSymbolSet*) syms;
@end
@interface ZBarReaderViewImpl
: ZBarReaderView
{
AVCaptureSession *session;
AVCaptureDevice *device;
AVCaptureInput *input;
}
@end
@implementation ZBarReaderViewImpl
@synthesize device, session;
- (void) _initWithImageScanner: (ZBarImageScanner*) scanner
{
[super _initWithImageScanner: scanner];
session = [AVCaptureSession new];
NSNotificationCenter *notify =
[NSNotificationCenter defaultCenter];
[notify addObserver: self
selector: @selector(onVideoError:)
name: AVCaptureSessionRuntimeErrorNotification
object: session];
[notify addObserver: self
selector: @selector(onVideoStart:)
name: AVCaptureSessionDidStartRunningNotification
object: session];
[notify addObserver: self
selector: @selector(onVideoStop:)
name: AVCaptureSessionDidStopRunningNotification
object: session];
[notify addObserver: self
selector: @selector(onVideoStop:)
name: AVCaptureSessionWasInterruptedNotification
object: session];
[notify addObserver: self
selector: @selector(onVideoStart:)
name: AVCaptureSessionInterruptionEndedNotification
object: session];
self.device = [AVCaptureDevice
defaultDeviceWithMediaType: AVMediaTypeVideo];
captureReader = [[ZBarCaptureReader alloc]
initWithImageScanner: scanner];
captureReader.captureDelegate = (id<ZBarCaptureDelegate>)self;
[session addOutput: captureReader.captureOutput];
if([session canSetSessionPreset: AVCaptureSessionPreset640x480])
session.sessionPreset = AVCaptureSessionPreset640x480;
[captureReader addObserver: self
forKeyPath: @"size"
options: 0
context: NULL];
[self initSubviews];
}
- (void) initSubviews
{
AVCaptureVideoPreviewLayer *videoPreview =
[[AVCaptureVideoPreviewLayer
layerWithSession: session]
retain];
preview = videoPreview;
CGRect bounds = self.bounds;
bounds.origin = CGPointZero;
preview.bounds = bounds;
preview.position = CGPointMake(bounds.size.width / 2,
bounds.size.height / 2);
videoPreview.videoGravity = AVLayerVideoGravityResizeAspectFill;
[self.layer addSublayer: preview];
[super initSubviews];
}
- (void) dealloc
{
[[NSNotificationCenter defaultCenter]
removeObserver: self];
if(showsFPS) {
@try {
[captureReader removeObserver: self
forKeyPath: @"framesPerSecond"];
}
@catch(...) { }
}
@try {
[captureReader removeObserver: self
forKeyPath: @"size"];
}
@catch(...) { }
captureReader.captureDelegate = nil;
[captureReader release];
captureReader = nil;
[device release];
device = nil;
[input release];
input = nil;
[session release];
session = nil;
[super dealloc];
}
- (void) updateCrop
{
[super updateCrop];
captureReader.scanCrop = effectiveCrop;
}
- (ZBarImageScanner*) scanner
{
return(captureReader.scanner);
}
- (void) setDevice: (AVCaptureDevice*) newdev
{
id olddev = device;
AVCaptureInput *oldinput = input;
assert(!olddev == !oldinput);
NSError *error = nil;
device = [newdev retain];
if(device) {
assert([device hasMediaType: AVMediaTypeVideo]);
input = [[AVCaptureDeviceInput alloc]
initWithDevice: newdev
error: &error];
assert(input);
}
else
input = nil;
[session beginConfiguration];
if(oldinput)
[session removeInput: oldinput];
if(input)
[session addInput: input];
[session commitConfiguration];
[olddev release];
[oldinput release];
}
- (BOOL) enableCache
{
return(captureReader.enableCache);
}
- (void) setEnableCache: (BOOL) enable
{
captureReader.enableCache = enable;
}
- (void) setTorchMode: (NSInteger) mode
{
[super setTorchMode: mode];
if(running && [device isTorchModeSupported: mode])
@try {
device.torchMode = mode;
}
@catch(...) { }
}
- (void) setShowsFPS: (BOOL) show
{
[super setShowsFPS: show];
@try {
if(show)
[captureReader addObserver: self
forKeyPath: @"framesPerSecond"
options: 0
context: NULL];
else
[captureReader removeObserver: self
forKeyPath: @"framesPerSecond"];
}
@catch(...) { }
}
- (void) start
{
if(started)
return;
[super start];
[session startRunning];
captureReader.enableReader = YES;
}
- (void) stop
{
if(!started)
return;
[super stop];
captureReader.enableReader = NO;
[session stopRunning];
}
- (void) flushCache
{
[captureReader flushCache];
}
- (void) configureDevice
{
if([device isFocusModeSupported: AVCaptureFocusModeContinuousAutoFocus])
device.focusMode = AVCaptureFocusModeContinuousAutoFocus;
if([device isTorchModeSupported: torchMode])
device.torchMode = torchMode;
}
- (void) lockDevice
{
if(!running || locked) {
assert(0);
return;
}
// lock device and set focus mode
NSError *error = nil;
if([device lockForConfiguration: &error]) {
locked = YES;
[self configureDevice];
}
else {
zlog(@"failed to lock device: %@", error);
// just keep trying
[self performSelector: @selector(lockDevice)
withObject: nil
afterDelay: .5];
}
}
// AVCaptureSession notifications
- (void) onVideoStart: (NSNotification*) note
{
zlog(@"onVideoStart: running=%d %@", running, note);
if(running)
return;
running = YES;
locked = NO;
[self lockDevice];
if([readerDelegate respondsToSelector: @selector(readerViewDidStart:)])
[readerDelegate readerViewDidStart: self];
}
- (void) onVideoStop: (NSNotification*) note
{
zlog(@"onVideoStop: %@", note);
if(!running)
return;
running = NO;
if(locked)
[device unlockForConfiguration];
else
[NSObject cancelPreviousPerformRequestsWithTarget: self
selector: @selector(lockDevice)
object: nil];
locked = NO;
if([readerDelegate respondsToSelector:
@selector(readerView:didStopWithError:)])
[readerDelegate readerView: self
didStopWithError: nil];
}
- (void) onVideoError: (NSNotification*) note
{
zlog(@"onVideoError: %@", note);
if(running) {
// FIXME does session always stop on error?
running = started = NO;
[device unlockForConfiguration];
}
NSError *err =
[note.userInfo objectForKey: AVCaptureSessionErrorKey];
if([readerDelegate respondsToSelector:
@selector(readerView:didStopWithError:)])
[readerDelegate readerView: self
didStopWithError: err];
else
NSLog(@"ZBarReaderView: ERROR during capture: %@: %@",
[err localizedDescription],
[err localizedFailureReason]);
}
// NSKeyValueObserving
- (void) observeValueForKeyPath: (NSString*) path
ofObject: (id) obj
change: (NSDictionary*) info
context: (void*) ctx
{
if(obj == captureReader &&
[path isEqualToString: @"size"])
// adjust preview to match image size
[self setImageSize: captureReader.size];
else if(obj == captureReader &&
[path isEqualToString: @"framesPerSecond"])
fpsLabel.text = [NSString stringWithFormat: @"%.2ffps ",
captureReader.framesPerSecond];
}
// ZBarCaptureDelegate
- (void) captureReader: (ZBarCaptureReader*) reader
didTrackSymbols: (ZBarSymbolSet*) syms
{
[self didTrackSymbols: syms];
}
- (void) captureReader: (ZBarCaptureReader*) reader
didReadNewSymbolsFromImage: (ZBarImage*) zimg
{
zlog(@"scanned %d symbols: %@", zimg.symbols.count, zimg);
if(!readerDelegate)
return;
UIImageOrientation orient = [UIDevice currentDevice].orientation;
if(!UIDeviceOrientationIsValidInterfaceOrientation(orient)) {
orient = interfaceOrientation;
if(orient == UIInterfaceOrientationLandscapeLeft)
orient = UIDeviceOrientationLandscapeLeft;
else if(orient == UIInterfaceOrientationLandscapeRight)
orient = UIDeviceOrientationLandscapeRight;
}
switch(orient)
{
case UIDeviceOrientationPortraitUpsideDown:
orient = UIImageOrientationLeft;
break;
case UIDeviceOrientationLandscapeLeft:
orient = UIImageOrientationUp;
break;
case UIDeviceOrientationLandscapeRight:
orient = UIImageOrientationDown;
break;
default:
orient = UIImageOrientationRight;
break;
}
UIImage *uiimg = [zimg UIImageWithOrientation: orient];
[readerDelegate
readerView: self
didReadSymbols: zimg.symbols
fromImage: uiimg];
}
@end

View File

@ -0,0 +1,219 @@
//------------------------------------------------------------------------
// Copyright 2010 (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
//------------------------------------------------------------------------
#import <ZBarSDK/ZBarReaderView.h>
#import <ZBarSDK/ZBarReaderViewController.h>
#define MODULE ZBarReaderView
#import "debug.h"
// hack around missing simulator support for AVCapture interfaces
// protected APIs
@interface ZBarReaderView()
- (void) _initWithImageScanner: (ZBarImageScanner*) _scanner;
- (void) initSubviews;
- (void) setImageSize: (CGSize) size;
- (void) didTrackSymbols: (ZBarSymbolSet*) syms;
@end
@interface ZBarReaderViewImpl
: ZBarReaderView
{
ZBarImageScanner *scanner;
UILabel *simLabel;
UIImage *scanImage;
CALayer *previewImage;
BOOL enableCache;
}
@end
@implementation ZBarReaderViewImpl
@synthesize scanner, enableCache;
- (void) _initWithImageScanner: (ZBarImageScanner*) _scanner
{
[super _initWithImageScanner: _scanner];
scanner = [_scanner retain];
[self initSubviews];
}
- (void) initSubviews
{
simLabel = [UILabel new];
simLabel.backgroundColor = [UIColor clearColor];
simLabel.textColor = [UIColor whiteColor];
simLabel.font = [UIFont boldSystemFontOfSize: 20];
simLabel.numberOfLines = 4;
simLabel.textAlignment = UITextAlignmentCenter;
simLabel.text = @"Camera Simulation\n\n"
@"Tap and hold with two \"fingers\" to select image";
simLabel.autoresizingMask =
UIViewAutoresizingFlexibleWidth |
UIViewAutoresizingFlexibleHeight;
[self addSubview: simLabel];
preview = [CALayer new];
[self.layer addSublayer: preview];
previewImage = [CALayer new];
[preview addSublayer: previewImage];
[super initSubviews];
}
- (void) dealloc
{
[scanner release];
scanner = nil;
[simLabel release];
simLabel = nil;
[previewImage release];
previewImage = nil;
[super dealloc];
}
- (AVCaptureDevice*) device
{
return(nil);
}
- (void) setDevice: (AVCaptureDevice*) device
{
// simulated camera does nothing with this
}
- (AVCaptureSession*) session
{
return(nil);
}
- (void) updateCrop
{
previewImage.frame = preview.bounds;
CGRect bounds = self.bounds;
simLabel.frame = CGRectInset(bounds,
bounds.size.width * .05,
bounds.size.height * .05);
}
- (void) start
{
if(started)
return;
[super start];
running = YES;
[self performSelector: @selector(onVideoStart)
withObject: nil
afterDelay: 0.5];
}
- (void) stop
{
if(!started)
return;
[super stop];
running = NO;
[self performSelector: @selector(onVideoStop)
withObject: nil
afterDelay: 0.5];
}
- (void) scanImage: (UIImage*) image
{
// strip EXIF info
CGImageRef cgimage = image.CGImage;
image = [[UIImage alloc]
initWithCGImage: cgimage
scale: 1.0
orientation: UIImageOrientationUp];
[self setImageSize: image.size];
[self layoutIfNeeded];
[CATransaction begin];
[CATransaction setDisableActions: YES];
previewImage.contentsGravity = kCAGravityResizeAspectFill;
previewImage.transform = CATransform3DMakeRotation(M_PI_2, 0, 0, 1);
previewImage.contents = (id)cgimage;
[CATransaction commit];
ZBarImage *zimg =
[[ZBarImage alloc]
initWithCGImage: cgimage];
CGSize size = zimg.size;
zimg.crop = CGRectMake(effectiveCrop.origin.x * size.width,
effectiveCrop.origin.y * size.height,
effectiveCrop.size.width * size.width,
effectiveCrop.size.height * size.height);
int nsyms = [scanner scanImage: zimg];
zlog(@"scan image: %@ crop=%@ nsyms=%d",
NSStringFromCGSize(size), NSStringFromCGRect(zimg.crop), nsyms);
[zimg release];
if(nsyms > 0) {
scanImage = [image retain];
ZBarSymbolSet *syms = scanner.results;
[self performSelector: @selector(didReadSymbols:)
withObject: syms
afterDelay: .4];
[self performSelector: @selector(didTrackSymbols:)
withObject: syms
afterDelay: .001];
}
[image release];
}
- (void) didReadSymbols: (ZBarSymbolSet*) syms
{
[readerDelegate
readerView: self
didReadSymbols: syms
fromImage: scanImage];
[scanImage release];
scanImage = nil;
}
- (void) onVideoStart
{
if(running &&
[readerDelegate respondsToSelector: @selector(readerViewDidStart:)])
[readerDelegate readerViewDidStart: self];
}
- (void) onVideoStop
{
if(!running &&
[readerDelegate respondsToSelector:
@selector(readerView:didStopWithError:)])
[readerDelegate readerView: self
didStopWithError: nil];
}
@end

197
iphone/ZBarSymbol.m Normal file
View File

@ -0,0 +1,197 @@
//------------------------------------------------------------------------
// Copyright 2009-2010 (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
//------------------------------------------------------------------------
#import <ZBarSDK/ZBarSymbol.h>
@implementation ZBarSymbol
@dynamic type, typeName, configMask, modifierMask, data, quality, count,
zbarSymbol;
+ (NSString*) nameForType: (zbar_symbol_type_t) type
{
return([NSString stringWithUTF8String: zbar_get_symbol_name(type)]);
}
- (id) initWithSymbol: (const zbar_symbol_t*) sym
{
if(self = [super init]) {
symbol = sym;
zbar_symbol_ref(sym, 1);
}
return(self);
}
- (void) dealloc
{
if(symbol) {
zbar_symbol_ref(symbol, -1);
symbol = NULL;
}
[super dealloc];
}
- (zbar_symbol_type_t) type
{
return(zbar_symbol_get_type(symbol));
}
- (NSString*) typeName
{
return([[self class] nameForType: zbar_symbol_get_type(symbol)]);
}
- (NSUInteger) configMask
{
return(zbar_symbol_get_configs(symbol));
}
- (NSUInteger) modifierMask
{
return(zbar_symbol_get_modifiers(symbol));
}
- (NSString*) data
{
return([NSString stringWithUTF8String: zbar_symbol_get_data(symbol)]);
}
- (int) quality
{
return(zbar_symbol_get_quality(symbol));
}
- (int) count
{
return(zbar_symbol_get_count(symbol));
}
- (zbar_orientation_t) orientation
{
return(zbar_symbol_get_orientation(symbol));
}
- (const zbar_symbol_t*) zbarSymbol
{
return(symbol);
}
- (ZBarSymbolSet*) components
{
return([[[ZBarSymbolSet alloc]
initWithSymbolSet: zbar_symbol_get_components(symbol)]
autorelease]);
}
- (CGRect) bounds
{
int n = zbar_symbol_get_loc_size(symbol);
if(!n)
return(CGRectNull);
int xmin = INT_MAX, xmax = INT_MIN;
int ymin = INT_MAX, ymax = INT_MIN;
for(int i = 0; i < n; i++) {
int t = zbar_symbol_get_loc_x(symbol, i);
if(xmin > t) xmin = t;
if(xmax < t) xmax = t;
t = zbar_symbol_get_loc_y(symbol, i);
if(ymin > t) ymin = t;
if(ymax < t) ymax = t;
}
return(CGRectMake(xmin, ymin, xmax - xmin, ymax - ymin));
}
@end
@implementation ZBarSymbolSet
@dynamic count, zbarSymbolSet;
@synthesize filterSymbols;
- (id) initWithSymbolSet: (const zbar_symbol_set_t*) s
{
if(!s) {
[self release];
return(nil);
}
if(self = [super init]) {
set = s;
zbar_symbol_set_ref(s, 1);
filterSymbols = YES;
}
return(self);
}
- (void) dealloc
{
if(set) {
zbar_symbol_set_ref(set, -1);
set = NULL;
}
[super dealloc];
}
- (int) count
{
if(filterSymbols)
return(zbar_symbol_set_get_size(set));
int n = 0;
const zbar_symbol_t *sym = zbar_symbol_set_first_unfiltered(set);
for(; sym; sym = zbar_symbol_next(sym))
n++;
return(n);
}
- (const zbar_symbol_set_t*) zbarSymbolSet
{
return(set);
}
- (NSUInteger) countByEnumeratingWithState: (NSFastEnumerationState*) state
objects: (id*) stackbuf
count: (NSUInteger) len
{
const zbar_symbol_t *sym = (void*)state->state; // FIXME
if(sym)
sym = zbar_symbol_next(sym);
else if(set && filterSymbols)
sym = zbar_symbol_set_first_symbol(set);
else if(set)
sym = zbar_symbol_set_first_unfiltered(set);
if(sym)
*stackbuf = [[[ZBarSymbol alloc]
initWithSymbol: sym]
autorelease];
state->state = (unsigned long)sym; // FIXME
state->itemsPtr = stackbuf;
state->mutationsPtr = (void*)self;
return((sym) ? 1 : 0);
}
@end

View File

@ -0,0 +1,23 @@
#!/bin/sh
set -ux
SUBTARGET=${1:?}
OUTDIR=${2:-$TARGET_BUILD_DIR}
# build library for device and simulator
xcodebuild -target $SUBTARGET -configuration $CONFIGURATION -sdk iphoneos BUILD_DIR=$BUILD_DIR BUILD_ROOT=$BUILD_ROOT\
|| exit 1
xcodebuild -target $SUBTARGET -configuration $CONFIGURATION -sdk iphonesimulator BUILD_DIR=$BUILD_DIR BUILD_ROOT=$BUILD_ROOT\
|| exit 1
mkdir -p $OUTDIR
# combine device and simulator libs into single fat lib.
# others have indicated that this approach is "wrong", but for us
# the ease of including the universal lib in a project without complicated
# changes to build settings outweighs any lack of purity in the approach
# ...we can always fix things later, if necessary
lipo -create \
$BUILD_ROOT/$CONFIGURATION-iphoneos/$SUBTARGET.a \
$BUILD_ROOT/$CONFIGURATION-iphonesimulator/$SUBTARGET.a \
-output $OUTDIR/$SUBTARGET.a \
|| exit 1

44
iphone/bin/CreateDMG.sh Normal file
View File

@ -0,0 +1,44 @@
#!/bin/sh
set -ux
VOLNAME=${1:?}
shift
RES=$SOURCE_ROOT/res
BUDDY=/usr/libexec/PlistBuddy
if [ ! -x "$BUDDY" ]; then
BUDDY=$(xcrun -find PlistBuddy) \
|| exit 1
fi
VERSION=$($BUDDY -c 'Print :CFBundleVersion' $RES/$VOLNAME-Info.plist) \
|| exit 1
DMG=$VOLNAME-$VERSION
mkdir -p $TARGET_BUILD_DIR/.background \
|| exit 1
cp -af $RES/$VOLNAME.DS_Store $TARGET_BUILD_DIR/.DS_Store
cp -af $RES/$VOLNAME-bg.png $TARGET_BUILD_DIR/.background/
# copy remaining arguments to image directly
for content
do
cp -af $content $TARGET_BUILD_DIR/ \
|| exit 1
done
# prepare examples for distribution
for example in $(find $TARGET_BUILD_DIR/Examples -depth 1 -not -name '.*')
do
rm -rf $example/{build,*.xcodeproj/{*.{mode1v3,pbxuser},project.xcworkspace,xcuserdata},ZBarSDK}
cp -af $BUILT_PRODUCTS_DIR/ZBarSDK $example/
done
# override subdir .DS_Stores
for dir in $(find $TARGET_BUILD_DIR -type d -depth 1)
do
cp -af $RES/Columns.DS_Store $dir/.DS_Store
done
hdiutil create -ov -fs HFS+ -format UDZO -imagekey zlib-level=9 \
-volname $VOLNAME \
-srcdir $TARGET_BUILD_DIR \
$BUILT_PRODUCTS_DIR/$DMG.dmg \
|| exit 1

View File

@ -0,0 +1,72 @@
#!/usr/bin/perl
# Quick hack script to generate the .DS_Store for the DMG, which
# * allows us to precisely position the window and icons
# * is more usefully versioned
# * avoids references to my local HD(!?)
use warnings;
use strict;
BEGIN {
use File::Spec::Functions qw(rel2abs splitpath);
use lib (splitpath(rel2abs($0)))[1];
}
use Data::Plist::BinaryWriter;
use Mac::Finder::DSStore qw(writeDSDBEntries makeEntries);
use Mac::Finder::AliasRecord;
$Mac::Finder::DSStore::Entry::types{bwsp} = 'blob';
$Mac::Finder::DSStore::Entry::types{icvp} = 'blob';
writeDSDBEntries($ARGV[0] || "DS_Store",
makeEntries(".",
bwsp => Data::Plist::BinaryWriter->new(serialize => 0)->write([
dict => {
WindowBounds => [
string => sprintf('{{%d, %d}, {%d, %d}}',
512, 128, 512, 608 + 22)
],
SidebarWidth => [integer => 0],
ShowToolbar => [false => 0],
ShowSidebar => [false => 0],
ShowPathbar => [false => 0],
ShowStatusBar => [false => 0],
}
]),
icvp => Data::Plist::BinaryWriter->new(serialize => 0)->write([
dict => {
viewOptionsVersion => [integer => 0],
arrangeBy => [string => "none"],
iconSize => [real => 64],
textSize => [real => 12],
labelOnBottom => [true => 1],
gridSpacing => [real => 100],
gridOffsetX => [real => 0],
gridOffsetY => [real => 0],
showItemInfo => [false => 0],
showIconPreview => [false => 0],
backgroundType => [integer => 2],
backgroundColorRed => [real => 0],
backgroundColorGreen => [real => 0],
backgroundColorBlue => [real => .5],
backgroundImageAlias => [
data => Mac::Finder::AliasRecord->new(
path => 'ZBarSDK:.background:ZBarSDK-bg.png',
volumeFS => 'HFS+')->write()
],
},
]),
vstl => "icnv",
),
makeEntries("README", Iloc_xy => [ 4.5 * 32, 2.5 * 32 ]),
makeEntries("ZBarSDK", Iloc_xy => [ 4.5 * 32, 7.5 * 32 ]),
makeEntries("ChangeLog", Iloc_xy => [ 4 * 32, 12.5 * 32 ]),
makeEntries("Documentation.html",
Iloc_xy => [ 8 * 32, 12.5 * 32 ]),
makeEntries("Examples", Iloc_xy => [ 12 * 32, 12.5 * 32 ]),
makeEntries("COPYING", Iloc_xy => [ 4 * 32, 16 * 32 ]),
makeEntries("LICENSE", Iloc_xy => [ 8 * 32, 16 * 32 ]),
makeEntries("Documentation",Iloc_xy => [ 12 * 32, 16 * 32 ]),
);

View File

@ -0,0 +1,169 @@
package Mac::Finder::AliasRecord;
# Generate(/Parse) a Mac "alias record" binary string/file.
#
# Currently just enough is implemented to satisfy immediate requirements
# (ie, write backgroundImageAlias to .DS_Store for DMG)
#
# based on these documents:
# http://www.geocities.com/xhelmboyx/quicktime/formats/alias-layout.txt
# http://sebastien.kirche.free.fr/python_stuff/MacOS-aliases.txt
#
# FIXME interface is very poor...
use warnings;
use strict;
use DateTime;
use File::Spec;
use File::Spec::Mac;
use Encode qw(encode);
require Exporter;
our $VERSION = '0.1';
our @ISA = qw(Exporter);
my %FSEncodings = (
MacFS => ['RW', ''],
MFS => ['RW', ''],
HFS => ['BD', ''],
'HFS+' => ['H+', ''],
AudioCD => ['', 'JH'],
ISO9660 => ['', 'AG'],
FAT => ['', 'IS'],
Joliet => ['', 'Jo'],
'ISO9660+Joliet' => ['', 'Jo'],
);
my %DiskEncodings = (
HD => 0,
FixedHD => 0,
Network => 1,
NetworkDisk => 1,
Floppy => 4,
Floppy1440 => 4,
Other => 5,
OtherDisk => 5,
);
my %RecordEncodings = (
parentDir => 0x00,
absolutePath => 0x02,
unicodeFile => 0x0e,
unicodeVolume => 0x0f,
volumePath => 0x12,
);
sub new {
my $class = shift || __PACKAGE__;
my $self = {
aliasCreator => '',
aliasVersion => 2,
aliasType => 'file',
volume => '',
volumeCreated => 0,
volumeFS => 'HFS',
volumeDisk => undef,
volumeAttrs => 0,
directoryID => 0,
file => '',
fileID => 0,
fileCreated => 0,
fileType => '',
fileCreator => '',
nlvlFrom => -1,
nlvlTo => -1,
records => { },
@_
};
if(exists($self->{path})) {
my $path = $self->{path};
my ($vol, $dir, $file) = File::Spec::Mac->splitpath($path);
$vol =~ s/:$//;
my @dir = File::Spec::Mac->splitdir($dir);
while(@dir && !$dir[0]) {
shift(@dir);
}
while(@dir && !$dir[-1]) {
pop(@dir);
}
$self->{volume} ||= $vol;
$self->{records}{unicodeVolume} ||=
pack('na*', length($vol), encode('utf-16be', $vol));
$self->{file} ||= $file;
$self->{records}{parentDir} ||= $dir[-1]
if(@dir);
$self->{records}{absolutePath} ||= $path;
$self->{records}{volumePath} ||= File::Spec->catfile('', @dir, $file);
$self->{records}{unicodeFile} ||=
pack('na*', length($file), encode('utf-16be', $file));
}
return(bless($self, ref($class) || $class));
}
sub toFSTime {
my $val = shift;
if(ref($val) && $val->isa("DateTime")) {
$val = $val->epoch - DateTime->new(year => 1904)->epoch();
}
return($val);
}
sub write {
my ($self, $out) = @_;
my $aliasType = $self->{aliasType};
$aliasType = (($aliasType =~ /^d(ir(ectory)?)?$/i && 1) ||
($aliasType !~ /^f(ile)?$/ && $aliasType) || 0);
my $volumeCreated = toFSTime($self->{volumeCreated});
my $volumeFS = $self->{volumeFS};
if(ref($volumeFS) ne 'ARRAY') {
$volumeFS = $FSEncodings{$volumeFS} || ['', ''];
}
my $volumeDisk = $self->{volumeDisk};
if(!defined($volumeDisk)) {
if($volumeFS->[0] eq 'H+') {
$volumeDisk = 'Floppy';
}
elsif($volumeFS->[0]) {
$volumeDisk = 'HD';
}
else {
$volumeDisk = 'Other';
}
}
$volumeDisk = (exists($DiskEncodings{$volumeDisk})
? $DiskEncodings{$volumeDisk}
: $volumeDisk);
my $fileCreated = toFSTime($self->{fileCreated});
my $buf =
pack('nn (C/a @28)Na2n N(C/a @64)NNa4a4 n!n!Na2 x10 (n!n/ax!2)*',
$self->{aliasVersion}, $aliasType,
$self->{volume}, $volumeCreated, $volumeFS->[0], $volumeDisk,
$self->{directoryID}, $self->{file}, $self->{fileID}, $fileCreated,
$self->{fileType}, $self->{fileCreator}, $self->{nlvlFrom},
$self->{nlvlTo}, $self->{volumeAttrs}, $volumeFS->[1],
map(((exists($RecordEncodings{$_}) ? $RecordEncodings{$_} : $_)
=> $self->{records}{$_}),
keys(%{$self->{records}})),
(-1, ''));
$buf = pack('a4n', $self->{aliasCreator}, length($buf) + 6) . $buf;
if(!$out) {
return($buf);
}
elsif(ref($out) eq 'GLOB') {
print $out $buf;
}
else {
open(my $outfh, '>', $out) || die;
print $outfh $buf;
}
}
1;

53
iphone/debug.h Normal file
View File

@ -0,0 +1,53 @@
//------------------------------------------------------------------------
// 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 <mach/mach_time.h>
#define xNSSTR(s) @#s
#define NSSTR(s) xNSSTR(s)
#ifdef DEBUG_OBJC
# ifndef MODULE
# define MODULE ZBarReaderController
# endif
# define zlog(fmt, ...) \
NSLog(NSSTR(MODULE) @": " fmt , ##__VA_ARGS__)
#define timer_start \
uint64_t t_start = timer_now();
#else
# define zlog(...) while(0)
# define timer_start
#endif
static inline uint64_t timer_now ()
{
return(mach_absolute_time());
}
static inline double timer_elapsed (uint64_t start, uint64_t end)
{
mach_timebase_info_data_t info;
mach_timebase_info(&info);
return((double)(end - start) * info.numer / (info.denom * 1000000000.));
}

View File

@ -0,0 +1,11 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
<meta http-equiv="Refresh" content="0; url=Documentation/index.html"/>
</head>
<body>
<p>redirecting to <a href="Documentation/index.html">Documentation/index.html</a></p>
</body>
</html>

150
iphone/doc/ZBarImage.rst Normal file
View File

@ -0,0 +1,150 @@
ZBarImage Class Reference
=========================
.. class:: ZBarImage
:Inherits from: :class:`NSObject`
A :class:`ZBarImage` is a wrapper for images passed to the barcode reader.
It encapsulates raw image data with the format and size metadata necessary
to interpret it.
An image must be wrapped in a :class:`ZBarImage` in order to be scanned by
the library. At least the format, size and data must be set. There are
also initialization methods for automatically extracting the data and
format from a `CGImage`.
This class is a wrapper around a :type:`zbar_image_t` C object (q.v.)
Properties
----------
.. member:: unsigned long format
The image format four-charcter code (fourcc) as a 4-byte integer. Use
:ref:`fourcc:<fourcc:>` to create a fourcc value from a string.
.. member:: unsigned sequence
A "sequence number" associated with the image. This reference value is
unused by the library.
.. member:: CGSize size
The size of the image in pixels.
.. note::
There is no separate "bytesPerLine" property, the width must match
the image data (which is not always the logical image width).
.. member:: CGRect crop
Optionally limit the scan region to this rectangle without having to
generate a cropped image.
.. member:: const void *data
Obtain a pointer to the raw image data. This property is read-only, use
:ref:`setData:withLength:<setData:withLength:>` to set the image data.
.. member:: unsigned long dataLength
Byte length of the raw image data. This property is read-only, use
:ref:`setData:withLength:<setData:withLength:>` to set the image data.
.. member:: ZBarSymbolSet *symbols
Barcode results from the last scan.
.. member:: zbar_image_t *zbarImage
Retrieve the underlying C object instance. (read-only)
.. member:: UIImage *UIImage
Convert the image to a UIImage. Only certain image formats are
supported for conversion (read-only)
:See also: :ref:`UIImageWithOrientation:<UIImageWithOrientation:>`
Class Methods
-------------
.. _`fourcc:`:
.. describe:: + (unsigned long) fourcc:(NSString*)format
Parse the integer four-character code from a string. Alternatively use
the :func:`zbar_fourcc` macro to create a constant expression.
:format: A four character string representing an image format.
:Returns: The corresponding 4-byte integer format code.
Instance Methods
----------------
.. _`initWithImage:`:
.. describe:: - (id) initWithImage:(zbar_image_t*)image
Initialize an image wrapper, given the C object to wrap.
:image: The C object to wrap.
:Returns: The initialized :class:`ZBarImage`.
.. _`initWithCGImage:`:
.. describe:: - (id) initWithCGImage:(CGImageRef)image
Initialize a :class:`ZBarImage` from the data and metadata extracted
from a `CGImage`. The image is converted to `Y800` (grayscale) format.
:image: A `CGImage` to source the data and metadata.
:Returns: The initialized :class:`ZBarImage`.
:See also: :ref:`initWithCGImage:size:<initWithCGImage:size:>`
.. _`initWithCGImage:size:`:
.. describe:: - (id) initWithCGImage:(CGImageRef)image size:(CGSize)size
Initialize a :class:`ZBarImage` from the data and metadata extracted
from a `CGImage`. The image is converted to `Y800` (grayscale) format
and scaled to the specified size.
:image: A `CGImage` to source the data and metadata.
:size: The pixel size of the resulting ZBarImage.
:Returns: The initialized :class:`ZBarImage`.
:See also: :ref:`initWithCGImage:crop:size:<initWithCGImage:crop:size:>`
.. _`initWithCGImage:crop:size:`:
.. describe:: - (id) initWithCGImage:(CGImageRef)image crop:(CGRect)crop size:(CGSize)size
Initialize a :class:`ZBarImage` from the data and metadata extracted
from a `CGImage`. The image is simultaneously converted to `Y800`
(grayscale) format, cropped and scaled to the specified size.
:image: A `CGImage` to source the data and metadata.
:crop: The region to convert, in image coordinates.
:size: The pixel size of the resulting ZBarImage.
:Returns: The initialized :class:`ZBarImage`.
.. _`setData:withLength:`:
.. describe:: - (void) setData:(const void*)data withLength:(unsigned long)length
Specify a pointer to the raw image data, for the image format and size.
The length of the data must also be provided. Note that the data must
remain valid as long as the image has a reference to it. Set data to
``NULL`` to clear a previous reference.
:data: A pointer to a raw image data buffer.
:length: The size of the image data buffer.
.. _`UIImageWithOrientation:`:
.. describe:: - (UIImage*) UIImageWithOrientation:(UIImageOrientation)orient
Convert the image to a UIImage with the specified orientation. Only
certain image formats are supported for conversion. (currently
``RGB3``, ``RGB4``, ``RGBQ``)
:orient: Desired orientation of the image.
:Returns: A new :class:`UIImage`, or ``nil`` in case of error.

View File

@ -0,0 +1,99 @@
ZBarImageScanner Class Reference
================================
.. class:: ZBarImageScanner
:Inherits from: :class:`NSObject`
This is a low-level interface for programmatically scanning images without
a user interface. If you want to scan images manually selected by the user
(from the photo library or using the camera), you may prefer to use a
:class:`ZBarReaderController` instead.
This class is a wrapper around a :type:`zbar_image_scanner_t` C object
(q.v.)
Properties
----------
.. member:: BOOL enableCache
Enable the inter-frame consistency cache. Set to ``YES`` for scanning
video or ``NO`` for scanning images.
.. member:: ZBarSymbolSet results
Decoded symbols resulting from the last scan.
Instance Methods
----------------
.. _`parseConfig:`:
.. describe:: - (void) parseConfig:(NSString*)config
Apply scanner/decoder configuration parsed from a string.
:config: A configuration setting of the form: `symbology.config[=value]`.
.. _`setSymbology:config:to:`:
.. describe:: - (void) setSymbology:(zbar_symbol_type_t)symbology config:(zbar_config_t)config to:(int)value
Apply generic scanner/decoder configuration.
:symbology: The symbology to effect, or 0 for all.
:config: The configuration setting to adjust.
:value: The value to set for the specific configuration/symbology.
.. _`scanImage:`:
.. describe:: - (NSInteger) scanImage:(ZBarImage*)image
Scan an image for barcodes using the current configuration. The image
must be in ``Y800`` format (8-bpp graysale).
:image: The :class:`ZBarImage` to scan.
:Returns: The number of barcode symbols decoded in the image.
Constants
---------
.. type:: zbar_config_t
ZBAR_CFG_ENABLE
Control whether specific symbologies will be recognized. Disabling
unused symbologies improves performance and prevents bad scans.
ZBAR_CFG_EMIT_CHECK
Whether to include the check digit in the result data string. This
value may be set individually for symbologies where it makes sense.
ZBAR_CFG_MIN_LEN
The minimum data length for a symbol to be valid, set to 0 to disable.
Use with eg, I2/5 to avoid short scans. This value may be set
individually for variable-length symbologies.
ZBAR_CFG_MAX_LEN
The maximum data length for which a symbol is valid, set to 0 to
disable. Use with eg, I2/5 to enforce a specific range of data lengths.
This value may be set individually for variable-length symbologies.
ZBAR_CFG_UNCERTAINTY
Number of "nearby" frames that must contain a symbol before it will be
considered valid. This value may be set for individual symbologies.
ZBAR_CFG_POSITION
Whether to track position information.
ZBAR_CFG_X_DENSITY
The stride to use for scanning vertical columns of the image. This many
pixel columns will be skipped between vertical scan passes. Useful for
trading off between resolution and performance. This is a scanner
setting (use 0 for the symbology).
ZBAR_CFG_Y_DENSITY
The stride to use for scanning horizontal columns of the image. This
many pixel rows will be skipped between horizontal scan passes. Useful
for trading off between resolution and performance. This is a scanner
setting (use 0 for the symbology).

View File

@ -0,0 +1,156 @@
ZBarReaderController Class Reference
====================================
.. class:: ZBarReaderController
:Inherits from: :class:`UIImagePickerController`
This is the controller to use for scanning images selected by a
:class:`UIImagePickerController` either captured manually using the camera,
or selected from the Photo Library. For more information, see
:doc:`picker`.
It can support automatic capture from the camera only if the library is
re-built to use private APIs (see :doc:`compat`).
Properties
----------
.. member:: ZBarImageScanner *scanner
Access to the image scanner for configuration. (read-only)
.. member:: id<ZBarReaderDelegate> readerDelegate
The delegate that will be notified when new barcode results are
available.
.. member:: BOOL showsZBarControls
Whether to display a default control set consisting of cancel, scan and
info buttons. Disable these if you provide your own controls using the
:member:`cameraOverlayView`. Enabling this automatically disables the
system controls :member:`showsCameraControls`. (Default ``YES``).
.. member:: BOOL showsHelpOnFail
Whether to automatically display the integrated help viewer when an
image fails to decode. Even if this is disabled, the integrated help
may still be presented manually using ``showHelpWithReason:``.
(Default ``YES``)
.. member:: ZBarReaderControllerCameraMode cameraMode
Scanning mode to use with the camera. It is generally appropriate to
leave this at the default.
.. member:: BOOL tracksSymbols
Whether to display the tracking rectangle around detected barcodes.
.. member:: BOOL takesPicture
Whether to take a full picture (with ``takePicture``) when a barcode
is detected with ``ZBarReaderControllerCameraModeSampling``. The
resulting image will be delayed from the actual decode.
.. member:: BOOL enableCache
This property is deprecated and should not be modified.
.. member:: CGRect scanCrop
Crop images before scanning. The original image will be cropped to this
rectangle, which should be in normalized image coordinates, x-axis
major. Defaults to the full image ``{{0, 0}, {1, 1}}``.
.. member:: NSInteger maxScanDimension
Scale image to scan. After cropping, the image will be scaled if
necessary, such that neither of its dimensions exceed this value.
Defaults to 640.
.. note::
The remaining properties are inherited from
:class:`UIImagePickerController`.
.. member:: UIImagePickerControllerSourceType sourceType
Image source. Use to select between the camera and photo library.
.. member:: BOOL showsCameraControls
Whether to display the system camera controls. Overridden to ``NO``
when :member:`showsZBarControls` is ``YES``.
.. member:: UIView *cameraOverlayView
A custom view to display over the camera preview. The tracking layer
and default controls will be added to this view if they are enabled.
.. member:: CGAffineTransform cameraViewTransform
A transform to apply to the camera preview. Ignored by the reader.
Possibly useful for eg, a digital zoom effect.
.. member:: BOOL allowsEditing
Whether to enable the system image editing dialog after a picture is
taken. Possibly useful to improve reader results in some cases using
manual intervention.
Instance Methods
----------------
.. _`showHelpWithReason:`:
.. describe:: - (void) showHelpWithReason:(NSString*)reason
Display the integrated help browser. Use this with custom overlays if
you don't also want to create your own help view. Should only be called
when the reader is displayed. The ``reason`` argument will be passed to
the :func:`onZBarHelp` javascript function.
:reason: A string parameter passed to javascript.
.. _`scanImage:`:
.. describe:: - (id <NSFastEnumeration>) scanImage:(CGImageRef)image
Scan an image for barcodes. This is a wrapper around
``scanner.scanImage`` that applies scanCrop and maxScanDimension. Some
additional result filtering is also performed.
:image: A :class:`CGImage` to scan.
:Returns: The result set containing :class:`ZBarSymbol` objects.
Constants
---------
.. type:: ZBarReaderControllerCameraMode
The scanning mode to use with the camera.
ZBarReaderControllerCameraModeDefault
The standard mode provided by UIImagePickerController - the user
manually captures an image by tapping a control. This is the default
unless private APIs are enabled.
ZBarReaderControllerCameraModeSampling
Automatically capture by taking screenshots with
:func:`UIGetScreenImage`. Resolution is limited to the screen
resolution, so this mode is inappropriate for longer codes. Only
available when private APIs are enabled, and becomes the default mode in
that case.
ZBarReaderControllerCameraModeSequence
Experimental mode that automatically scans by "rapidly" scanning
pictures captured with ``takePicture``. Not recommended for serious
use.
.. c:var:: NSString *ZBarReaderControllerResults
The info dictionary key used to return decode results to
``imagePickerController:didFinishPickingMediaWithInfo:``

View File

@ -0,0 +1,70 @@
ZBarReaderDelegate Protocol Reference
=====================================
.. class:: ZBarReaderDelegate
:Inherits from: :class:`UIImagePickerControllerDelegate`
This protocol must be implemented by the
:member:`~ZBarReaderViewController::readerDelegate` provided to a
:class:`ZBarReaderViewController` or :class:`ZBarReaderController`. It is
used to notify the delegate of new decode results, when an image fails to
decode, or when the user dismisses the reader with the built-in controls.
Instance Methods
----------------
.. describe:: - (void) imagePickerController:(UIImagePickerController*)picker didFinishPickingMediaWithInfo:(NSDictionary*)info
This inherited delegate method is called when a barcode is successfully
decoded. The decoded symbols are available from the dictionary as a
:class:`ZBarSymbolSet` using the :c:data:`ZBarReaderControllerResults`
key. The image from which the barcodes were scanned is available using
the :c:data:`UIImagePickerControllerOriginalImage` key. No other keys
are guaranteed to be valid.
.. note::
The ``picker`` parameter will be the reader controller instance that
read the barcodes - not necessarily a
:class:`UIImagePickerController` instance. You should cast it to the
correct type for anything other than basic view controller access.
:picker: The reader controller that scanned the barcode(s).
:info: A dictionary containing the image and decode results.
.. describe:: - (void) imagePickerControllerDidCancel:(UIImagePickerController*)picker
Called when the user taps the "Cancel" button provided by the built-in
controls (when :member:`showsZBarControls`\ ``=YES``). The default
implementation dismisses the reader. If this method is implemented, it
should do the same.
.. note::
The ``picker`` parameter will be the reader controller instance that
read the barcodes - not necessarily a
:class:`UIImagePickerController` instance. You should cast it to the
correct type for anything other than basic view controller access.
:picker: The reader controller that scanned the barcode(s).
.. describe:: - (void) readerControllerDidFailToRead:(ZBarReaderController*)reader withRetry:(BOOL)retry
Called when an image, manually captured or selected from the photo
library, is scanned and no barcodes were detected.
If the ``retry`` parameter is ``NO``, the controller must be dismissed
before this method returns. Otherwise, another scan may be attempted
without re-presenting the controller.
If the :member:`~ZBarReaderController::showsHelpOnFail` is ``YES`` *and*
``retry`` is ``YES``, the integrated help viewer will already be
presenting.
If this method is not implemented, the controller will be dismissed iff
``retry`` is ``NO``.
:reader: The :class:`ZBarReaderController` that scanned the barcode(s).
:retry: Whether another scan may be attempted.

View File

@ -0,0 +1,126 @@
ZBarReaderView Class Reference
==============================
.. class:: ZBarReaderView
:Inherits from: :class:`UIView`
This is a barcode reader encapsulted in a UIView. It manages an
:class:`AVCaptureSession` with a camera device and a
:class:`ZBarCaptureReader`, presents the video preview and optionally
tracks detected barcode symbols. A delegate will usually be assigned for
notification of new decode results.
Properties
----------
.. member:: id<ZBarReaderViewDelegate> readerDelegate
The delegate that will be notified of new decode results.
.. member:: ZBarImageScanner *scanner
Access to the image scanner is provided for configuration. (read-only)
.. member:: BOOL tracksSymbols
Whether to display the tracking annotation (default ``YES``).
.. member:: UIColor *trackingColor
The color of the tracking annotation (default green).
.. member:: BOOL allowsPinchZoom
Enable pinch gesture recognition for manually zooming the preview/decode
(default ``YES``).
.. member:: NSInteger torchMode
An :type:`AVCaptureTorchMode` value that will be applied if/when
appropriate. (default Auto)
.. member:: BOOL showsFPS
Overlay the decode frame rate on the preview to help with performance
optimization. This is for *debug only* and should not be set for
production. (default ``NO``)
.. member:: CGFloat zoom
Zoom scale factor applied to the video preview *and* scanCrop. This
value is also updated by the pinch-zoom gesture. Valid values are in
the range [1,maxZoom]. (default 1.25)
.. member:: CGFloat maxZoom
Maximum settable zoom level. The zoom property will be clipped to this
value.
.. member:: CGRect scanCrop
The region of the video image that will be scanned, in normalized image
coordinates. Note that the video image is in landscape mode (default
{{0, 0}, {1, 1}})
.. member:: CGAffineTransform previewTransform
Additional transform that will be applied to the video preview. Note
that this transform is *not* applied to scanCrop.
.. member:: AVCaptureDevice *device
The capture device may be manipulated or replaced.
.. member:: AVCaptureSession *session
Direct access to the capture session. Warranty void if opened.
(read-only)
.. member:: ZBarCaptureReader *captureReader
Direct access to the capture reader. Warranty void if opened.
(read-only)
.. member:: BOOL enableCache
:Deprecated:
Whether to use the inter-frame consistency cache. This should always be
set to ``YES``.
Instance Methods
----------------
.. describe:: - (id) initWithImageScanner:(ZBarImageScanner*)imageScanner
:imageScanner: A pre-configured :class:`ZBarImageScanner` to use for scanning
:Returns: The initialized :class:`ZBarReaderView`
.. describe:: - (void) start
Begin/resume scanning after a call to ``stop``.
.. describe:: - (void) stop
Stop scanning and pause the video feed.
.. describe:: - (void) flushCache
Flush the inter-frame consistency cache. Any barcodes in the frame will
be re-recognized in subsequent frames.
.. _`setZoom:animated:`:
.. describe:: - (void) setZoom:(CGFloat)zoom animated:(BOOL)animated
Set the zoom property with optional animation.
.. _`willRotateTointerfaceOrientation:duration:`:
.. describe:: - (void) willRotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation duration:(NSTimeInterval)duration
Compensate for device / camera / interface orientation. Must be called
by containing view controller that supports any non-portrait orientation
to restore the camera preview to the correct orientation. Call from
view controller method of the same name for correct animation.

View File

@ -0,0 +1,190 @@
ZBarReaderViewController Class Reference
========================================
.. class:: ZBarReaderViewController
:Inherits from: :class:`UIViewController`
This is the controller to use for live scanning from the camera feed with
automatic capture. For scanning from image files or with manual capture,
see :class:`ZBarReaderController`.
Properties
----------
.. member:: ZBarImageScanner *scanner
Access to the image scanner for configuration. (read-only)
.. member:: id <ZBarReaderDelegate> readerDelegate
The delegate that will be notified when new barcode results are
available.
.. member:: BOOL showsZBarControls
Whether to display a default control set consisting of cancel, scan and
info buttons. Disable these if you provide your own controls using the
:member:`cameraOverlayView`. (Default ``YES``).
.. member:: BOOL tracksSymbols
Whether to display the tracking rectangle around detected barcodes.
.. member:: NSUInteger supportedOrientationsMask
Set of interface orientations that the controller should support. Use
:func:`ZBarOrientationMask` or ``ZBarOrientationMaskAll`` to
generate the mask.
.. member:: CGRect scanCrop
Crop images before scanning. The original image will be cropped to this
rectangle, which should be in normalized image coordinates (NB the
camera image x-axis is *vertical* on the screen). Defaults to the full
image ``{{0, 0}, {1, 1}}``.
.. member:: UIView *cameraOverlayView
A custom view to display over the camera preview.
.. member:: CGAffineTransform cameraViewTransform
A transform to apply to the camera preview. Ignored by the reader.
.. member:: UIImagePickerControllerCameraDevice cameraDevice
The camera device to use for scanning. Defaults to the system default
camera.
.. member:: UIImagePickerControllerCameraFlashMode cameraFlashMode
The "flash" (aka torch) mode to use while scanning. Defaults to
UIImagePickerControllerCameraFlashModeAuto.
.. member:: UIImagePickerControllerQualityType videoQuality
The resolution to use while scanning. Defaults to
UIImagePickerControllerQuality640x480.
.. member:: ZBarReaderView *readerView
View that presents the camera preview and performs the scanning. This
view has other properties you may use to control the appearance and
behavior of the reader.
Note that this view may be released when it is not displayed (eg, under
low memory conditions). You should apply any configuration just before
you present the reader.
.. member:: BOOL enableCache
This property is deprecated and should not be modified.
.. warning::
The remaining properties are deprecated, they are only present for
backward compatibility with :class:`ZBarReaderController` and will raise
an exception if inappropriate/unsupported values are set.
.. member:: UIImagePickerControllerSourceType sourceType
Raises an exception if anything other than
``UIImagePickerControllerSourceTypeCamera`` is set. If you want to scan
images, use a :class:`ZBarReaderController` instead of this class.
.. member:: UIImagePickerControllerCameraCaptureMode cameraCaptureMode
Raises an exception if anything other than
``UIImagePickerControllerCameraCaptureModeVideo`` is set.
.. member:: BOOL allowsEditing
Raises an exception if anything other than ``NO`` is set.
.. member:: BOOL showsCameraControls
Raises an exception if anything other than ``NO`` is set. Use
:member:`showsZBarControls` to disable the buit-in overlay.
.. member:: BOOL showsHelpOnFail
Any value set to this property is ignored. It is only useful for
scanning images, for which you should use :class:`ZBarReaderController`.
.. member:: ZBarReaderControllerCameraMode cameraMode
This reader only supports scanning from the camera feed. If you want to
scan manually captured images, use a :class:`ZBarReaderController`
instead of this class.
.. member:: BOOL takesPicture
Raises an exception if anything other than ``NO`` is set. This
controller automatically returns the scanned camera frame and does not
support capturing a separate image.
.. member:: NSInteger maxScanDimension
Any value set to this property is ignored. It is only useful for
scanning images, for which you should use :class:`ZBarReaderController`.
Class Methods
-------------
.. describe:: + (BOOL) isSourceTypeAvailable:(UIImagePickerControllerSourceType)source
Returns ``YES`` only if ``source`` is ``Camera`` and the
:class:`UImagePickerController` method of the same name also returns
``YES``.
.. describe:: + (BOOL) isCameraDeviceAvailable:(UIImagePickerControllerCameraDevice)cameraDevice
See the :class:`UImagePickerController` method of the same name.
.. describe:: + (BOOL) isFlashAvailableForCameraDevice:(UIImagePickerControllerCameraDevice)cameraDevice
See the :class:`UImagePickerController` method of the same name.
.. describe:: + (NSArray*) availableCaptureModesForCameraDevice:(UIImagePickerControllerCameraDevice)cameraDevice
Returns an array with the single element
``UIImagePickerControllerCameraCaptureModeVideo`` if the device is
avilable, otherwise returns an empty array.
Instance Methods
----------------
.. _`showHelpWithReason:`:
.. describe:: - (void) showHelpWithReason:(NSString*)reason
Display the integrated help browser. Use this with custom overlays if
you don't also want to create your own help view. Should only be called
when the reader is displayed. The ``reason`` argument will be passed to
the :func:`onZBarHelp` javascript function.
:reason: A string parameter passed to javascript.
.. _`takePicture`:
.. describe:: - (void) takePicture
Capture the next available frame and send it over the usual delegate
path.
Macros
------
.. function:: ZBarOrientationMask(interfaceOrientation)
Generate a bit-mask for the specified interface orientation, suitable
for setting :member:`supportedOrientationsMask`.
.. describe:: ZBarOrientationMaskAll
Combination of :func:`ZBarOrientationMask` for all interface
orientations (Portrait, PortraitUpsideDown, LandscapeLeft and
LandscapeRight)

View File

@ -0,0 +1,26 @@
ZBarReaderViewDelegate Protocol Reference
=========================================
.. class:: ZBarReaderViewDelegate
:Inherits from: :class:`NSObject`
This protocol, which must be implemented by the `readerDelegate` provided
to a :class:`ZBarReaderView`, is used to notify the delegate of new decode
results.
Instance Methods
----------------
.. describe:: - (void) readerView:(ZBarReaderView*)readerView didReadSymbols:(ZBarSymbolSet*)symbols fromImage:(UIImage*)image
Called to notify the delegate of new decode results.
Note that the referenced image is a proxy for a video buffer that is
asynchronously being converted to a :class:`UIImage`, attempting to
access the data will block until the conversion is complete.
:readerView: :class:`ZBarReaderView` that scanned the barcode(s).
:symbols: :class:`ZBarSymbolSet` containing the decode results.
:image: :class:`UIImage` from which the barcode(s) were scanned.

186
iphone/doc/ZBarSymbol.rst Normal file
View File

@ -0,0 +1,186 @@
ZBarSymbol Class Reference
==========================
.. class:: ZBarSymbol
:Inherits from: :class:`NSObject`
A symbol wraps all of the information the library has about a decoded
barcode. Use the available properties to retrieve the barcode data, the
symbology (type of barcode), location and more.
This class is a simple wrapper around a :type:`zbar_symbol_t` C object
(q.v.)
Properties
----------
.. member:: zbar_symbol_type_t type
The type of symbology that was decoded. (read-only)
.. member:: NSString *typeName
The canonical name used by the library to represent the symbology.
(read-only)
.. member:: NSUInteger configMask
Bitmask of symbology config settings used during decode.
.. member:: NSUInteger modifierMask
Bitmask of symbology characteristics detected during decode. See
:type:`zbar_modifier_t` for the currently defined modifier bits.
.. member:: NSString *data
The raw decoded barcode data. (read-only)
.. member:: int quality
A relative metric indicating rough confidence in the decoded value.
Larger values are better than smaller values. (read-only)
.. member:: zbar_orientation_t orientation
The general, axis-aligned orientation of the symbol, or
ZBAR_ORIENT_UNKNOWN if unknown. (read-only)
.. member:: ZBarSymbolSet *components
The components of a composite symbol. (read-only)
.. member:: const zbar_symbol_t *zbarSymbol
Retrieve the underlying C object instance. (read-only)
.. member:: CGRect bounds
Calculate a rough bounding box for the symbol. (read-only)
.. note::
Coordinates are relative to the image *data*, which may not match a
displayed UIImage. Make sure to account for the UIImage orientation
when using these values.
Class Methods
-------------
.. _`nameForType:`:
.. describe:: + (NSString*) nameForType:(zbar_symbol_type_t)type
Retrieve the canonical name for a symbology used by the library, given
its enumerated value.
:type: The :type:`zbar_symbol_type_t` enumerated symbology value.
:Returns: A short string name for the symbology.
Instance Methods
----------------
.. _`initWithSymbol:`:
.. describe:: - (id) initWithSymbol:(const zbar_symbol_t*)symbol
Initialize a symbol wrapper, given the C object to wrap.
:symbol: The C object to wrap.
:Returns: The initialized symbol, or nil if an error occurred.
Constants
---------
.. type:: zbar_symbol_type_t
Symbology identifiers.
ZBAR_NONE
No symbol was decoded.
ZBAR_PARTIAL
Intermediate status.
ZBAR_EAN8
EAN-8
ZBAR_UPCE
UPC-E
ZBAR_ISBN10
ISBN-10, converted from EAN-13
ZBAR_UPCA
UPC-A
ZBAR_EAN13
EAN-13
ZBAR_ISBN13
ISBN-13, converted from EAN-13
ZBAR_I25
Interleaved 2 of 5
ZBAR_DATABAR
GS1 DataBar (RSS)
ZBAR_DATABAR_EXP
GS1 DataBar Expanded
ZBAR_CODABAR
Codabar
ZBAR_CODE39
Code 39 (3 of 9)
ZBAR_QRCODE
QR Code
ZBAR_CODE128
Code 128
.. type:: zbar_orientation_t
The coarse orientation of a symbol.
.. note::
Orientation is relative to the image *data*, which may not match a
displayed UIImage. Make sure to account for the UIImage orientation
when using these values.
ZBAR_ORIENT_UNKNOWN
Unable to determine orientation.
ZBAR_ORIENT_UP
Upright, read left to right
ZBAR_ORIENT_RIGHT
Sideways, read top to bottom
ZBAR_ORIENT_DOWN
Upside-down, read right to left
ZBAR_ORIENT_LEFT
Sideways, read bottom to top
.. type:: zbar_modifier_t
Decoder symbology modifier flags.
.. note::
These are bit indices, use eg, (1 << ZBAR_MOD_GS1) to test the
modifierMask property.
ZBAR_MOD_GS1
Barcode tagged as GS1 (EAN.UCC) reserved (eg, FNC1 before first data
character). Data may be parsed as a sequence of GS1 AIs.
ZBAR_MOD_AIM
Barcode tagged as AIM reserved.

View File

@ -0,0 +1,43 @@
ZBarSymbolSet Class Reference
=============================
.. class:: ZBarSymbolSet
:Inherits from: :class:`NSObject`
:Conforms to: :class:`NSFastEnumeration`
A symbol set is a simple container for the symbols scanned from an image.
It supports :class:`NSFastEnumeration`, and not much else... Use it to
iterate through the :class:`ZBarSymbol` objects in a decode result set::
ZBarSymbolSet *symbols = image.symbols;
for(ZBarSymbol *symbol in symbols) {
// process result
}
This class is a simple wrapper around a :type:`zbar_symbol_set_t` C object
(q.v.)
Properties
----------
.. member:: int count
The number of symbols in the set. (read-only)
.. member:: const zbar_symbol_set_t *zbarSymbolSet
Retrieve the underlying C object instance. (read-only)
Instance Methods
----------------
.. _`initWithSymbolSet:`:
.. describe:: - (id) initWithSymbolSet:(const zbar_symbol_set_t*)set
Initialize a symbol set wrapper, given the C object to wrap.
:set: The C object to wrap.
:Returns: The initialized symbol set, or nil if an error occurred.

16
iphone/doc/apiref.rst Normal file
View File

@ -0,0 +1,16 @@
*******************
API Reference
*******************
.. toctree::
:maxdepth: 1
ZBarImage
ZBarImageScanner
ZBarReaderController
ZBarReaderDelegate
ZBarReaderView
ZBarReaderViewController
ZBarReaderViewDelegate
ZBarSymbol
ZBarSymbolSet

130
iphone/doc/camera.rst Normal file
View File

@ -0,0 +1,130 @@
Scanning From the Camera Feed
=============================
Many iOS developers want their application to support automatic recognition of
barcodes from the camera feed in real-time. ZBar makes this easy!
There are three levels that you may choose to integrate at, from least complex
(recommended) to most complex these are:
* Use the fully integrated view controller - this is very easy to implement
and is the recommended approach.
* Use the reader view with your own controller - this more advanced approach
allows you to embed the view directly in your view hierarchy.
* Use the capture component with your own AVCapture session - this is not
supported and only provided for advanced developers with special needs who
are already familiar with AVCapture.
Using a ZBarReaderViewController
--------------------------------
This is the fastest, easiest and recommend way to get the barcode reader into
your application. The procedure is the same as using a
UIImagePickerController to take a picture with the camera, so it will help if
you are familiar with that. Basically you:
1. Create the reader.
This is as simple as creating a new :class:`ZBarReaderViewController`::
ZBarReaderViewController *reader = [[ZBarReaderViewController alloc] init];
2. Setup a delegate to receive the results.
The delegate should implement the :class:`ZBarReaderDelegate` protocol,
which inherits from :class:`UIImagePickerControllerDelegate`::
reader.readerDelegate = self;
3. Configure the reader.
Aside from the properties of the reader itself, you can configure the
decoder via the :member:`~ZBarReaderViewController::scanner` property and
further customize the view via the
:member:`~ZBarReaderViewController::readerView` property::
// disable QR Code
[reader.scanner setSymbology: ZBAR_QRCODE
config: ZBAR_CFG_ENABLE
to: 0];
reader.readerView.zoom = 1.0;
See :doc:`custom` and :doc:`optimizing` for more details.
4. Present the reader to the user.
Typically the controller is presented modally::
[self presentModalViewController: reader
animated: YES];
Alternatively, it may be added to a container controller.
5. Process the results.
The controller will call the
``imagePickerController:didFinishPickingMediaWithInfo:`` method of
your delegate every time new results become available. The barcode data
can be obtained using the :c:data:`ZBarReaderControllerResults` key of the
info dictionary. This key will return "something enumerable"; keep in mind
that there may be multiple results. You may also retrieve the
corresponding image with :c:data:`UIImagePickerControllerOriginalImage` as
usual::
- (void) imagePickerController: (UIImagePickerController*) reader
didFinishPickingMediaWithInfo: (NSDictionary*) info
{
id<NSFastEnumeration> results =
[info objectForKey: ZBarReaderControllerResults];
UIImage *image =
[info objectForKey: UIImagePickerControllerOriginalImage];
...
The ``reader`` parameter will be the actual type of the reader (not
necessarily a :class:`UIImagePickerController`).
.. note::
The delegate method should queue the interface response and return as
soon as possible; any processing of the results should be deferred until
later, otherwise the user will experience unacceptable latency between
the actual scan completion and the visual interface feedback.
6. Dismiss the reader (or not).
Once you have the results you may dismiss the reader::
[reader dismissModalViewControllerAnimated: YES];
.. warning::
It is very important to dismiss from the *reader* (not the presenting
controller) to avoid corrupting the interface.
Alternatively, you may choose to continue scanning and provide visual
feedback another way (eg, maybe by updating your custom overlay with the
results). The "continuous" mode of the readertest example does this.
Using a ZBarReaderView
----------------------
:class:`ZBarReaderViewController` is a relatively thin wrapper around a
:class:`ZBarReaderView`; it is possible to use the view directly, even from
Interface Builder. You lose only some of the simulator and rotation hooks.
The documentation is also less complete, so you need to be able to UTSL. See
the :file:`EmbedReader` sample for a working example.
Using the ZBarCaptureReader
---------------------------
If you have special requirements for the capture session or just want to use
your own preview, you can add your own :class:`ZBarCaptureReader` to your
session. You must have a solid understanding of the AVCapture infrastructure
if you plan to use this approach.
.. admonition:: TBD
sorry, you're on your own here - UTSL :)

190
iphone/doc/compat.rst Normal file
View File

@ -0,0 +1,190 @@
Backward Compatibility
======================
Generally speaking, we take great care to ensure that each release of the
library is backward compatible with previous versions - upgrading the library
should not require any changes to your code and will continue to provide
equivalent functionality. The notable exception to this is the iOS 4 upgrade
and associated "deprecation" of the former automatic capture method by our
vendor.
.. warning::
Versions before iOS 4 are no longer supported by the library. We are no
longer able to test anything in this section, so you're on your own if you
try to make use of it.
The Private API
---------------
The API that we use for automatic capture with iOS 3.x (namely
:func:`UIGetScreenImage`) has an interesting history. It has changed status
several times, starting with "Private, unless we like you" moving to
"reluctantly Public but undocumeted" by popular demand and reverting to
"strictly Private" as of iOS 4. The current story: if you want to distribute
on the App Store, you had better not be using it - IOW, no automatic capture
for you with iOS 3.x.
Since App Store distribution is the most common use for the library, the
default configuration, and thus the binary SDK, does *not* use any private
APIs.
Users targeting ad-hoc or enterprise distribution may not care about the
status of the API and may prefer to continue supporting automatic capture for
iOS 3.x. To do this you will need to rebuild the library with the following
define set for all configurations:
.. sourcecode:: sh
USE_PRIVATE_APIS=1
For reference, you can check whether your app refers to the offensive function
with this command:
.. sourcecode:: sh
$ otool -vI MyApp.app/MyApp | grep UIGetScreenImage
If there is any output, then the executable includes the private API and is
bound to be rejected if submitted for review. Otherwise it is "clean" as far
as this library is concerned.
Upgrading to iOS 4
------------------
If you were using the reader before iOS 4 was introduced, you will want to
upgrade to the new reader controller. The performance has improved quite a
bit, and you can continue to support automatic capture on the App Store.
.. note::
This discussion only applies to automatic capture from the camera. If you
are only scanning image files, or prefer/need to use manual capture, you
should not change anything.
Basically just replace your old :class:`ZBarReaderController` with a new
:class:`ZBarReaderViewController` and you're done! See the reference and the
next section for compatibility between the two classes.
Also see the :doc:`install` instructions for details about upgrading the
header references to use the SDK.
Supporting iOS 3.x
------------------
The new :class:`ZBarReaderViewController` is intentionally designed to be
compatible with the old :class:`ZBarReaderController` in most aspects that
relate to reading barcodes. When a :class:`ZBarReaderViewController` is
initialized under iOS 3.x, it will *replace* itself with a
:class:`ZBarReaderController`. You can leverage the compatibility of these
controllers to continue supporting iOS 3.x.
The following properties and methods should be equivalent across
implementations. You may use them without regard for the actual instance
type.
======================================================== ====
Equivalent Members
======================================================== ====
:member:`~ZBarReaderViewController::cameraOverlayView`
:member:`~ZBarReaderViewController::cameraViewTransform`
:member:`~ZBarReaderViewController::enableCache`
:member:`~ZBarReaderViewController::scanner`
:member:`~ZBarReaderViewController::readerDelegate`
:member:`~ZBarReaderViewController::scanCrop`
``showHelpWithReason:``
:member:`~ZBarReaderViewController::showsZBarControls`
:member:`~ZBarReaderViewController::tracksSymbols`
======================================================== ====
Some properties are available with :class:`ZBarReaderViewController` only for
backward compatibility. If these are configured, they must be set as
indicated; attempts to set another value will raise an exception.
==================================================== =======================================
:class:`ZBarReaderController` Property :class:`ZBarReaderViewController` Value
==================================================== =======================================
:member:`~ZBarReaderController::allowsEditing` ``NO``
:member:`~ZBarReaderController::cameraMode` ``Sampling``
:member:`~ZBarReaderController::maxScanDimension` (ignored)
:member:`~ZBarReaderController::showsCameraControls` ``NO``
:member:`~ZBarReaderController::showsHelpOnFail` (ignored)
:member:`~ZBarReaderController::sourceType` ``Camera``
:member:`~ZBarReaderController::takesPicture` ``NO``
==================================================== =======================================
Also, the ``isSourceTypeAvailable:`` class method of
:class:`ZBarReaderViewController` will return ``YES`` only for the ``Camera``
source.
All other members of :class:`ZBarReaderController`, including those inherited
from :class:`UIImagePickerController` are not supported by
:class:`ZBarReaderViewController`. This includes ``takePicture`` and
``scanImage:``, among others.
Remaining members of :class:`ZBarReaderViewController`: are only available
with the new implementation. At the moment this is only
:member:`~ZBarReaderViewController::readerView`, but any new properties or
methods not listed here will also fall in this category.
To access settings that may not be available in a potential fallback
environment, you must verify that they exist and may be set as desired - eg,
by testing the specific reader subtype.
Weak Linking
^^^^^^^^^^^^
When leveraging fallbacks to iOS 3.x, it is important that features introduced
in iOS 4 are referenced using *weak* links. You must configure your project
correctly to support this:
* Make sure the iOS 4 frameworks are set to *Weak*. Specifically, these are
AVCapture, CoreMedia and CoreVideo.
* Build with the latest SDK - do *not* use the "Base SDK" setting to target
earlier devices.
* Set the correct iOS 3.x version for the "iPhone OS Deployment Target"
build setting.
Example: Fallback to Manual Capture
-----------------------------------
This code example will configure the reader for automatic capture from the
camera for iOS 4 and fall back to manual or automatic capture for iOS 3.x,
depending on whether the library was compiled to use private APIs::
if(![ZBarReaderController isSourceTypeAvailable:
UIImagePickerControllerSourceTypeCamera]) {
// camera unavailable: display warning and abort
// or resort to keypad entry, etc...
return;
}
ZBarReaderViewController *reader = [ZBarReaderViewController new];
// reader will be a ZBarReaderController for iOS 3.x
// or a ZBarReaderViewController for iOS 4
reader.readerDelegate = self;
reader.sourceType = UIImagePickerControllerSourceTypeCamera;
reader.showsZBarControls = YES;
if(reader.cameraMode == ZBarReaderControllerCameraModeSampling) {
// additional automatic capture configuration here
}
else {
// additional manual capture configuration here
}
[self presentModalViewController: reader
animated: YES];
If you are using a custom control set
(:member:`~ZBarReaderViewController::showsZBarControls`\ ``=NO``), you will
want to provide a button attached to ``takePicture`` for the manual capture
case. The built-in controls do this automatically.

77
iphone/doc/conf.py Normal file
View File

@ -0,0 +1,77 @@
import sys, os
from plistlib import readPlist
# General configuration
extensions = []
templates_path = ['ext']
source_suffix = '.rst'
master_doc = 'index'
exclude_patterns = ['.#*']
project = u'ZBar iPhone SDK'
copyright = u'2010-2012, Jeff Brown et al'
today_fmt = '%Y-%m-%d'
info = readPlist('../res/ZBarSDK-Info.plist')
version = 'X.Y'
if info:
version = info['CFBundleVersion']
release = version
#add_module_names = False
pygments_style = 'sphinx'
highlight_language = 'objc'
primary_domain = 'cpp'
# Options for HTML output
html_theme = 'default'
html_theme_options = {
'bgcolor': 'white',
'textcolor': 'black',
'linkcolor': '#247',
'headbgcolor': '#edeff0',
'headtextcolor': '#247',
'headlinkcolor': '#c11',
'sidebarbgcolor': '#247',
'sidebartextcolor': 'white',
'sidebarlinkcolor': '#cde',
'relbarbgcolor': '#247',
'relbartextcolor': '#ccc',
'relbarlinkcolor': 'white',
'footerbgcolor': 'white',
'footertextcolor': 'black',
'codebgcolor': '#dfe',
'codetextcolor': 'black',
}
html_short_title = 'ZBarSDK ' + version
html_title = 'ZBar iPhone SDK Documentation'
html_static_path = ['static']
html_favicon = '../../zbar.ico'
html_style = 'style.css'
html_use_modindex = False
html_use_index = False
html_copy_source = False
html_show_sourcelink = False
htmlhelp_basename = 'doc'
# Options for LaTeX output
latex_paper_size = 'letter'
latex_font_size = '10pt'
# Grouping the document tree into LaTeX files. List of tuples
# (source start file, target name, title, author, documentclass [howto/manual])
latex_documents = [
('index', 'ZBarSDK.tex', u'ZBar iPhone SDK Documentation',
u'Jeff Brown', 'manual'),
]
#latex_logo = ''
#latex_use_parts = False
#latex_preamble = ''
#latex_appendices = []
#latex_use_modindex = False

70
iphone/doc/custom.rst Normal file
View File

@ -0,0 +1,70 @@
Customizing the Interface
=========================
The reader supports customization of the camera overlay and the integrated
help that is displayed.
Customizing the Overlay
-----------------------
If you are scanning with the camera, whether using a
:class:`ZBarReaderViewController` for automatic capture or manually with
:class:`ZBarReaderController`, you may want to customize the appearance of the
reader. You do this mainly by setting a
:member:`~ZBarReaderViewController::cameraOverlayView`.
Note that if you are scanning images from the photo library, there is no
customization - you are limited to the system picker interface provided by the
:class:`UIImagePickerController`.
If you are using a :class:`ZBarReaderViewController` and just want to add to
the existing controls, you can simply set your overlay to include the
additional view hierarchy::
reader.cameraOverlayView = myLogoImageView;
Otherwise, if you are using a :class:`ZBarReaderController` or prefer to
completely replace the default controls, you should disable those first. Note
that you will need to provide your own controls, which should at least include
a way to dismiss the reader::
reader.showsCameraControls = NO; // for UIImagePickerController
reader.showsZBarControls = NO;
reader.cameraOverlayView = myControlView;
For manual capture with :class:`ZBarReaderController`, you should also include
a control connected to :member:`~ZBarReaderController::takePicture`.
In either case, the overlay view may be loaded from a NIB, or simply created
programmatically.
You can also disable the tracking rectangle that highlights barcodes with
:member:`~ZBarReaderViewController::tracksSymbols`.
Presenting Help
---------------
If you have set ``showsZBarControls = NO`` and replaced the default controls,
you may still present the built-in help viewer. Just hook your custom control
to the ``showsHelpWithReason:`` method of the controller. You should only
call this method when the reader is actually presented.
The default reader controls invoke ``showsHelpWithReason:`` with a reason
parameter of ``"INFO"`` when the info button is tapped.
Customizing the Help Content
----------------------------
Whether you use the default controls or provide your own, you can still
customize the content of the help that is displayed. The integrated viewer
uses a UIWebView to display the contents of :file:`zbar-help.html` that we
copied into your Resources. You should hack this up as you see fit to give
your users the best help experience.
To allow for runtime customization based on the reason for presenting help,
the javascript function ``onZBarHelp`` will be called just before the page is
displayed, with the ``reason`` argument set as provided to
``showsHelpWithReason:``.

13
iphone/doc/devguide.rst Normal file
View File

@ -0,0 +1,13 @@
***********************
Developer's Guide
***********************
.. toctree::
:maxdepth: 2
camera
picker
custom
optimizing
compat
licensing

101
iphone/doc/faq.rst Normal file
View File

@ -0,0 +1,101 @@
Frequently Asked Questions (FAQ)
================================
This is the ever-growing list of answers to commonly asked questions. Please
feel free to post you question in our `iPhone Developers forum`_ if you do not
find the information you need in this documentation.
.. _`iPhone Developers Forum`:
http://sourceforge.net/projects/zbar/forums/forum/1072195
General
-------
This looks great... Where can I get it?
You can download the latest version of the SDK from
http://zbar.sf.net/iphone
Compatibility
-------------
Which iPhone devices does this library support?
The library works *only* with iOS devices that have an auto-focus camera.
Currently, the iPhone 3GS, iPhone 4 and newer devices. The iPad 2 and iPad
3 will also work in many cases, *iff* the barcode is printed large enough
to achieve good focus.
Will you make it work with the iPhone 3G?
*No* - the 3G it is not supported and is unlikely to ever be supported.
To be fair, you *can* use the 3G to scan image files, as long as they're in
focus (ie, *not* images taken by the built-in fixed-focus camera). There
is at least one application that found a use for this...
What target iOS versions does this library work with?
iOS 4, 5 and 6 are fully supported, including the latest video streaming
interfaces. Since Apple has dropped support for earlier versions of iOS on
the App Store, we recommend that you target only iOS 4 and later for reading
barcodes.
Note that iOS 3.1 is no longer supported; if you really think you need
that, you should still be able to get it working... See :doc:`compat` for
details about iOS version fallbacks.
In all cases you should use the latest SDK to build.
Are any private APIs in use?
No - the binary release of the SDK does not use any private APIs.
Does this support "automatic" barcode capture?
Yes - with recent iOS versions, the default configuration will capture
barcodes automatically from the video stream.
Building
--------
I get "Undefined symbols" errors when I try to build?
Most likely you did not add all of the necessary framework dependencies.
See :doc:`tutorial` or :doc:`install` for the list of frameworks you need
to link against.
Licensing
---------
Please refer to :doc:`licensing` for questions about licensing.
Barcodes
--------
Why do my UPC barcodes have an extra 0 at the front?
The UPC-A_ symbology is the subset of EAN-13_ that starts with a leading 0.
The ZBar decoder enables only EAN-13_ by default, so GTIN-13_ product codes
are consistently reported. You can choose to receive the 12-digit results
instead by explicitly enabling UPC-A_.
The :member:`~ZBarSymbol::type` property of the symbol can be used to see
which type of barcode is reported.
See EAN-13_ and UPC-A_ for more information.
Why does my UPC-E (short version) barcode data look completely wrong?
UPC-E_ is a "zero compressed" version of UPC-A_; certain of the zeros are
removed from the UPC-A_ data to generate the UPC-E_ barcode. The ZBar
decoder *expands* this compression by default, again to consistently report
GTIN-13_ product codes. You can choose to receive the compressed 8-digit
results instead by explicitly enabling UPC-E_.
The :member:`~ZBarSymbol::type` property of the symbol can be used to see
which type of barcode is reported.
See UPC-E_ for more information.
.. _GTIN-13:
.. _GTIN: http://wikipedia.org/wiki/GTIN
.. _EAN-13: http://wikipedia.org/wiki/EAN-13
.. _UPC-A: http://wikipedia.org/wiki/UPC-A
.. _UPC-E: http://wikipedia.org/wiki/UPC-E#UPC-E

12
iphone/doc/getstarted.rst Normal file
View File

@ -0,0 +1,12 @@
*********************
Getting Started
*********************
.. toctree::
:maxdepth: 2
:numbered:
install
tutorial
faq
support

20
iphone/doc/index.rst Normal file
View File

@ -0,0 +1,20 @@
################
ZBar iOS SDK
################
Welcome to the ZBar SDK for iOS!
This documentation covers all aspects of developing with the SDK: from adding
the SDK to your project, to writing code that uses it, even licensing the
library with your app.
Please let us know if you find anything inaccurate or lacking (even better,
send doc patches!)
.. toctree::
:maxdepth: 2
:numbered:
getstarted
devguide
apiref

141
iphone/doc/install.rst Normal file
View File

@ -0,0 +1,141 @@
Installing the SDK
==================
These are the basic instructions for obtaining the SDK and adding it to an
Xcode project.
You may want to try things out with the :doc:`tutorial` before hacking at your
own project.
Requirements
------------
You will need *all* of the following to develop iPhone applications
using this SDK:
* Mac OS X >= 10.6.x (Snow Leopard)
* Xcode >= 4.5.1
* iPhone SDK >= 4.0
* An iPhone 3GS, iPhone 4 or newer iOS device with an auto-focus camera
* iOS >= 4.0 running on the device
.. warning::
*Only* the iPhone 3GS, iPhone 4 and newer models are supported, as they
have a camera with auto-focus. The iPad 2 and iPad 3 will also work, *iff*
the barcode is printed large enough to achieve good focus. The ZBar
library does not support the iPhone 3G and is unlikely to ever support it.
Downloading
-----------
Download the latest binary release of the ZBar SDK from
http://zbar.sourceforge.net/iphone
Integration
-----------
The recommended installation method is to simply copy the SDK into your
Xcode project:
1. Open ZBarSDK-|version|.dmg in the Finder.
2. Drag the :file:`ZBarSDK` folder into your Xcode project. In the dialog
that appears, you should choose to **copy** the SDK into your project by
checking the box. The target that you want to link with the library should
also be selected in the target list.
3. Link the following additional frameworks to any targets that link with the
ZBarSDK. You should set the first three to use weak references and
configure an appropriate deployment target if you still need to support
iOS 3:
* :file:`AVFoundation.framework` (weak)
* :file:`CoreMedia.framework` (weak)
* :file:`CoreVideo.framework` (weak)
* :file:`QuartzCore.framework`
* :file:`libiconv.dylib`
If you check "Link Binary With Libraries" for the target(s), you should see
all of these frameworks followed by :file:`libzbar.a`.
.. note::
Link order may be important for some versions of Xcode; the referenced
libraries should be listed *before* :file:`libzbar.a` in the link order.
4. Import the SDK header from your prefix header to make the barcode reader
APIs available::
#import "ZBarSDK.h"
Proceed to :doc:`camera` or :doc:`picker` to learn about using the reader APIs
to scan barcodes. Use the :doc:`apiref` for specific interface details.
Upgrading from an Older Version
-------------------------------
If you are using an older version of the *SDK* (NB, skip to the next section
if you are currently using Mercurial), upgrading is straightforward:
1. Delete the current ZBarSDK group from your project. You should choose
to delete the files if you copied them into your project.
2. Drag the new ZBarSDK from the DMG into your project.
Clean out and rebuild your project with the new version.
Upgrading a Pre-SDK Integration
-------------------------------
If your project was using the library directly from the Mercurial repository,
before the SDK was introduced, there are a few incompatibilities that you must
resolve in order to upgrade. Don't worry - all of your source stays the same,
you just need to update how the library is included in the project and how the
headers are imported.
Switching to the Binary Distribution
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
This approach is recommended - the binary releases provide you with a stable
development platform, isolating you from temporary instability and transient
problems that may occur at the bleeding edge.
The first task is to reverse the previous ZBar integration:
1. Remove the reference to zbar.xcodeproj from your project.
2. Remove any :file:`zbar-*` files from your Resources.
3. In the target build settings, remove any "Header Search Paths" that
reference zbar.
4. Remove any references to zbar headers in your :file:`prefix.pch` or source
files.
Now just continue with the `integration`_ instructions above and you should be
back up and running!
Continuing with Mercurial
^^^^^^^^^^^^^^^^^^^^^^^^^
Alternatively, you may still prefer to select Mercurial revisions. You have a
few choices for this:
* You may build your own ZBarSDK and copy/link it into your project. This is
the same as `Switching to the Binary Distribution`_, except that you use
your own version of the SDK. In this case you need to manually rebuild the
SDK when you update it.
* You may leave zbar.xcodeproj as a project dependency and pull the SDK into
your project. This is not well tested, so ymmv.
* You may leave zbar.xcodeproj as a project dependency and just link libzbar.a
into your project, as before. You will need to update the target dependency
(the library target changed names to libzbar) and add the
:file:`iphone/include/ZBarSDK` directory to "Header Search Paths"
In any case, you should remove the references to the zbar headers from
:file:`prefix.pch` (or your source files) and replace them with::
#import "ZBarSDK.h"

187
iphone/doc/licensing.rst Normal file
View File

@ -0,0 +1,187 @@
Licensing the Library
=====================
First of all, the big disclaimer:
.. warning::
We are *not* lawyers; we cannot help you decide if you should use the
library or how to apply the license, only your lawyer can advise you
concerning legal matters.
That said, it should also be noted that we have neither the resources (time,
cash, etc) nor the patience to enforce the license (at all); the reality is
that all of this is left to your discretion.
If you prefer to leave the lawyers out of it, the rest of this section will
help you apply the license to your application.
Licensing FAQ
-------------
Can I use this library with my proprietary (closed source) application?
Yes, that is our intent and we do not believe there is any problem
regarding the license.
Will I need to open source my entire app?
No, it is not required by the license.
Will I need to distribute all of my "object files" on the App Store?
No, this is also not required by the license, although you should offer to
provide them upon request. See below for more detail.
But I read somewhere that "iPhone apps may not use LGPL code"?
That statement is an over-generalization that does not apply in this case.
Most likely your source is either:
* referring to the GPL, which is significantly different from the
*L*\ GPL
* referring to a different version of the LGPL; we intentionally use
version 2.1, which has specific static linking exceptions.
* not a lawyer either and too lazy to read the whole license
Basically, if you leverage the appropriate sections of the license, it
should be fully compatible with the App Store restrictions and
requirements.
This is too complicated, can I just pay for an easier license?
No, it is not possible. There are multiple problems with this approach,
some brief highlights:
* Most open source projects (including this one) do not have a single
author. Tracking down every contributor and getting their approval could
be quite a challenge.
* The license is meant to protect users' rights to the software. Giving
you special treatment bypasses the protection we offered them,
effectively revoking their rights. This would be a violation of their
trust and completely defeats the purpose of the license.
You may think of this as the "price" you pay for using our open source
library. If you want to make your life easier, you should be petitioning
Apple for shared library support...
What if you add a clause that lets me do whatever I want?
No, also not possible. In addition to the problems mentioned above, there
are even more problems with this:
* Sourceforge requires an OSI approved license for hosting our project;
an altered license would no longer be approved.
* Again we are not lawyers and therefore not qualified to change the
license, we would have to pay one of those slimy buggers to do it.
Do I need to add an "about" dialog to display your copyright/license?
No, not as such. We won't discourage you from plugging the library if you
like, but it is not a requirement. You should think of our license as a
supplement to your own software license, therefore it is appropriate to
display it where (and only where) you display your own:
* If you follow Apple's recommendation, the App Store is the only place
that the user accesses your license, so it should also be the only place
where the library supplement is available.
* If your app already has some kind of "about" view that displays your
copyright/license information, it is also appropriate to display the same
information for the library.
Do I need to include the entire library in my application bundle?
No, it is not necessary:
* If you have not modified the library, it is sufficient to provide a link
to the project and the version information.
* If you are using a modified version, you may provide a link to download
that instead of including it in the bundle.
Modifications
-------------
What is a "modification"? Again, we leave it to your discretion with this
guidance:
* If you use the distributed binary SDK you have certainly not modified the
library.
* If you are working from Mercurial, *any* change you have made to the
"source code" of the library is a modification, it does not matter how
trivial. You can see what changes have been made by running
``hg status -mard``; if this command outputs anything, you have modified
the library.
If you find that you have made changes to the library, you should carefully
consider how far you want to proceed down that path. Once you publish your
changes you have created a "fork" of the project which you now need to
maintain. Are you prepared to merge every time the library is updated?
If your change adds a useful feature to the library, we absolutely encourage
you to submit patches. Assuming you can get your patch into the project, then
you will no longer need to use a modified version! When submitting patches,
ensure that your changes are appropriate for all of our users. Specifically,
we are not interested in patches that simply hack up the library to work the
way you want. Compare a patch that changes the default behavior to your
preference (probably not acceptable), to a patch that adds a new configuration
to support the feature you have added (probably fine).
Object File Distribution
------------------------
Section 6 of the LGPL v2.1 specifically permits static linking with the
library. If your project is not open source, this section does require that
you make your object files available to your users. The intent, as indicated
in the license, is that a user who has obtained your software may exercise
their right to modify the library and then re-link their modified version into
your application.
We recommend that you apply Subsection 6c, which only requires that you make a
written offer to provide the object files. Now...if you consider the actual
utility of this mechanism - that it is only applicable to developers, and only
those with in depth knowledge of the tools, the time required for development
- all to have a new barcode reader in a specific version of your application
that only they can use, the reality is that no one is going to request this.
You probably should not even waste time preparing for it until a request is
made.
Additionally, to avoid "casual requests" from nefarious types that just want
to inconvenience you, also consider charging a fee for the distribution of
this material (as permitted by the license); just add up the cost of burning
and shipping a disk. If this cost is "large" compared to the price of your
app, the likelyhood of a request is reduced even further.
Using the Unmodified Library
----------------------------
Applying the license in this case is somewhat simpler. These are the basic
steps you can follow:
1. Verify that the rest of your software license is compatible with the LGPL.
You cannot use the library if they are incompatible.
For those using the default App Store license, we have reviewed this and
believe it is compatible with the LGPL.
2. At the end of your license text, in an annex or supplement, start by
declaring your use of the library and offering a link to the project.
Something like this:
This software uses the open source ZBar Barcode Reader library, version
|version|, which is available from http://zbar.sourceforge.net/iphone
If you built your own version of the library, replace the version callout
with eg, "cloned from Mercurial revision xxxxxxxx"
3. Then append the contents of the text file COPYING, included with the
library. This is all of the copyright information for the library.
4. Then append the contents of the text file LICENSE, also included with the
library. This is just the LGPL version 2.1 which you may also obtain from
http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html
5. You may choose to make the written offer for the object files explicit.
Provide some text and whatever link or email address is appropriate.
Using a Modified Library
------------------------
We intentionally leave this option vague and force you to refer to the license
as an underhanded way of encouraging you to contribute back to the project ;)

435
iphone/doc/optimizing.rst Normal file
View File

@ -0,0 +1,435 @@
Optimizing the Reader
=====================
As good as the iPhone performance is for a mobile device, the reality from an
image processing perspective is that it represents a lower performance target.
While the default configuration of the iPhone reader has been carefully tuned
for the general case, you can often obtain much better results if you optimize
for your specific application.
.. note::
Performance is a complex topic. The only way to tune performance is by
changing settings and comparing measured results. If you are not
comfortable with the concepts presented here, it is recommended that you
leave the settings at the defaults and avoid compromising reliability.
Performance of the barcode reader is generally evaluated by two factors:
* The **latency** - how quickly it "recognizes" a barcode. Specifically this
is the time from when the user puts a barcode in the frame or selects an
image until a response is indicated back to the them.
* The **reliability** - it does not matter how quickly an image is scanned if
an incorrect result is returned. That may seem obvious, but bad decodes
*are* possible and you need to keep this in mind when changing settings that
affect the reliability of the reader.
Basically our goal is to optimize the latency without sacrificing reliability.
There are several factors that contribue to latency:
* The **quality** of the barcode image. Quality includes the available
resolution, focus, lighting, noise, etc. We have more control over some of
these than others.
* The **camera**. When scanning from the camera, the time for the
autoexposure and autofocus to converge on an image that can be decoded is a
significant contribution to the overall latency.
* The **frame rate** of the reader - this translates to the time it takes the
scanner to process an image.
* The **effort level** of the reader - some of the available settings control
"how hard" the reader tries to find barcodes in each frame.
* The **delegate latency** - the time spent in your application after a
barcode has been detected until the user is notified.
Most of these factors are interrelated. We will discuss those we can control
in detail, as well the settings you use to affect them. Then we will provide
a few specific case examples.
Measuring Performance
---------------------
Subjective response times are a good place to start (does it "feel" responsive
to you?), and possibly the only way to evaluate the overall experience, but to
compare incremental changes to interrelated settings and have meaningful
performance discussions with others, we need a more quantitative approach.
The :func:`mach_absolute_time` function is a good tool for accurately
measuring small delays. Research this function and learn how to apply it. As
when measuring any real-world value, keep in mind that some variance is to be
expected - even if you perform exactly the same operation multiple times, you
will not see exactly the same measurement. You should collect several
samples, discard any obvious outliers, and average the remaining measurements.
One way that the overall reader latency may be evaluated is by manually
marking the time when the barcode is presented to the reader. Add a control
to your overlay that captures the start time when tapped and compare this to
the end time, just before your delegate returns.
The reader continually monitors the frame rate at which it is running. The
measured value may be displayed for debugging purposes by enabling the
:member:`~ZBarReaderView::showsFPS` property. The readertest example does
this and also provides control over many of the available settings, so you can
quickly test how each setting affects the frame rate. You should target your
optimization efforts to achieve a frame rate of at least 8-10fps, although
12-15fps is preferable.
You can measure the latency of your delegate using :func:`mach_absolute_time`.
The measured value should be less than about 100ms, the smaller the better, to
avoid noticeable lag.
The readertest is a good tool for testing the performance of the reader. You
can tune the settings appropriately for your application and evaluate the
effect each change has on the performance.
Delegate Latency
----------------
This latency contributor is the easiest for you to effect (and sometimes the
easiest to overlook). Your delegate method should update the interface -
dismiss the controller or update your overlay to indicate success - and
*nothing* else. All other processing should be deferred until after the
animations have started.
Image Quality
-------------
Resolution
^^^^^^^^^^
One might think that "more is better" in terms of resolution, but this is not
necessarily the case. Given average image quality, the ideal resolution for
scanning is right around three pixels per barcode "module" (the width of the
smallest bar or space). Note that this measure is not an absolute image size
or even a measure of the physical dimensions represented by a pixel sample, it
*only* describes the sampled size of the barcode in the image.
As the resolution decreases below about two pixels per module, edge fidelity
is lost and the bars and spaces start to merge together, making it impossible
(for this library) to scan. This affects the density (feature size) and
maximum size (data capacity) of the barcodes that can be detected.
Conversely, as the resolution increases above about 4 pixels per module, noise
can interfere with the edge detection and images will take longer to process.
Other quality factors, such as poor focus, bad lighting or even excessive
noise, can increase (or decrease) the resolution requirement.
When scanning from the camera, the reader defaults to 640x480, which is good
for most applications. On newer devices, you can increase this using a capture
:member:`~ZBarReaderView::session` preset. Some older devices do not have a
higher resolution option available.
For scanning images, you can use
:member:`~ZBarReaderController::maxScanDimension` to control the scaled size
of the converted image, or resort to converting them yourself.
If you want to read long linear barcodes or dense 2-D symbols, you will
probably want to increase the resolution by adjusting these settings.
Keep in mind that more pixels will take longer to scan, refer to the `frame
rate`_ discussion for ways to compensate.
Focus
^^^^^
Ideally we would fix the focus at a calculated optimum distance and optimize
the aperture selection to maximize the depth of field. Unfortunately the APIs
do not currently give us control over any of these settings, the best we can
do (as of iOS 4) is continuous auto-focus mode - this mode is configured by
the reader automatically. It can still take the device as long as 1-2 seconds
to find the appropriate macro focus setting, but again, there is currently no
way to reduce this delay.
Lighting and Exposure
^^^^^^^^^^^^^^^^^^^^^
An image that is too bright or overexposed can completely wash out any
barcodes. An image that is too dark or underexposed will not provide
sufficient contrast for the scanner. Low light levels also tend to produce
noisier images, possibly because the driver uses a faster "ISO" setting to
compensate for the lighting.
The camera defaults to continuous automatic exposure and white balance. Since
there are no other useful values, the reader leaves these unchanged from their
default setting.
For some devices, the "torch" can be enabled to provide additional
illumination for the camera in low-light conditions. The reader sets the
torch to automatic by default, so it should turn on only when needeed...
There have been some reports that the torch turns on inappropriately, washing
out the image. If you find that this occurs, you should instead set the
:member:`~ZBarReaderView::torchMode` property of the :class:`ZBarReaderView`
to ``Off``.
For scanning images from another source, you are again stuck with the
available image quality. If you have any control over the image source, you
should do what you can to fix quality problems there.
Noise
^^^^^
Some level of noise is filtered by the reader, but excessive noise levels
create additional edges in the image which corrupt barcodes and increase
scanning time (decreasing the frame rate).
As mentioned with `lighting and exposure`_, noise mostly becomes a problem
when the light-level is too low, but high-resolution images may also increase
exposure to sensor noise.
We compensate for noise by *reducing* the `resolution`_ from the sensor
maximum. Scaling the image down has the effect of averaging several pixels
into one value, filtering out the high-frequency noise component.
Frame Rate
----------
The time it takes to scan and decode an image/frame is roughly proportional to
the number of pixels that are processed. The number and type of enabled
symbologies and image noise can also affect the processing time.
We have several knobs available that affect the frame rate. Most of these are
geared toward reducing the number of image pixels that are scanned.
Decrease the Resolution
^^^^^^^^^^^^^^^^^^^^^^^
Adjusting the resolution of the image is an easy way to quickly reduce the
number of pixels. Smaller images also mean there is less data to carry
around, which helps performance in other ways. For example, reducing each
image dimension by 30% (eg, from 640x480 to 448x336) will about double the
speed of the reader (to a point). [FIXME verify!]
Adjusting the resolution is `described above <resolution>`_. As mentioned
there, reducing the resolution will negatively impact the minimum feature size
and maximum barcode size that can be scanned, but it will help filter noise.
Crop the Scan Region
^^^^^^^^^^^^^^^^^^^^
It may not always be necessary for an application to scan all the way to the
edges of the image. By cropping the scan area, you can get most of the
benefits of reduced resolution without sacrificing the minimum feature size.
Cropping will also not affect image noise, but similar to decreasing the
resolution, it does affect the maximum size barcode that can be scanned.
For all cases you set the crop rectangle
:class:`~ZBarReaderViewController::scanCrop` property. Note that the
rectangle provided to the controller is *normalized* across image size and
rotation. This means that the coordinates range from 0 to 1 and the axes will
be arranged such that the x-axis of the crop rectangle corresponds to the
major (longer) image axis.
Your interface will typically need to indicate the cropped scan area to the
user with visual queues. Use the
:class:`~ZBarReaderViewController::cameraOverlayView` to provide this.
By default, the :class:`ZBarReaderView` recognizes a pinch gesture to
digitally zoom the preview around the center of the image. This zoom does not
affect the resolution of the image, but it does crop the scan region to the
visible area. You can also disable the pinch gesture and set the
:class:`~ZBarReaderView::zoom` programmatically.
Limit the Scan Density
^^^^^^^^^^^^^^^^^^^^^^
The scanner works by making scan passes across the pixel rows and colums of
the image. The density of the passes is configured at the scanner as a pixel
stride for each axis. ``ZBAR_CFG_Y_DENSITY`` (``ZBAR_CFG_X_DENSITY``)
controls the number of pixel rows (columns) that are skipped between
successive horizontal (vertical) scan passes. (Note that "density" is really
not a good name for the configuation settings... "stride" might be more
appropriate.)
Decreasing the scan density (by increasing the stride setting) is a great way
to limit the processing (increasing the frame rate) without sacrificing scan
resolution - each scan pass is still made at full image resolution, there are
just fewer passes (less redundancy).
Setting the stride value to 0 completely disables scanning in that direction.
This is very useful when reading linear codes with a visual alignment guide -
scanning parallel to the bars is a waste of cycles which may be better applied
to support higher resolution or increased density of scans across the symbol.
Note that some 2-D symbologies (QR Code) require scans in both directions.
Setting the stride to a very large value will generate a single scan pass
through the center of the image. Note that some symbologies will not be
detected without multiple successful passes; it is usually better to combine
this setting with cropping to generate a number of closely clustered scan
passes in the target area.
Note that the density also affects the aspect ratio and rotation that can be
tolerated. If you set it too large, some barcodes will become more difficult
to read.
In general, 2 to 4 is a good target for the stride setting, unless you have
very high or low resolution images.
Disable unused symbologies
^^^^^^^^^^^^^^^^^^^^^^^^^^
Limiting the symbologies to the set of interest should provide a small
performance boost. It also improves decode reliability - it is impossible to
receive an incorrect or unexpected decode result from a symbology that is
disabled.
The reader does support full auto-discrimination among the supported
symbologies, but with all of them enabled you may need to compensate elsewhere
to get a good frame rate.
For example, if you are only interested in QR codes, disable the others. The
robust way to do this is by disabling *all* symbologies and then reenabling
only those you want. This helps isolate you from encountering new symbologies
that may be added in future versions of the library until you are ready to
handle them::
[scanner setSymbology: 0
config: ZBAR_CFG_ENABLE
to: 0];
[scanner setSymbology: ZBAR_QRCODE
config: ZBAR_CFG_ENABLE
to: 1];
Even if you would like your application to support multiple symbologies, you
may consider if there is a way to limit the enabled subset based on the
scanning context, etc...
Examples
--------
These examples demonstrate several scenarios for scanning from the camera with
automatic capture. You can try them yourself using the readertest. For each
example, start with the default settings (by tapping the
``ZBarReaderViewController`` class), then enable continuous mode and the
custom overlay (by disabling
:member:`~ZBarReaderViewController::showsZBarControls`). You should also use
a release build and avoid running in the debugger.
Frame rates are approximate, measured on an iPhone 3GS running iOS 4.0.1 in a
well lit room. Two measurements are taken for each sample: the rate with the
camera pointed at a blank white page such that it fills the frame, and the
rate while continuously decoding the provided example. For best results, it
is recommended that you print the examples rather than scanning them from the
screen.
For reference, the base frame rates with default settings are 12fps for a
blank white page, 7.5fps for this `basic EAN symbol`_ and 2.2fps for this
`basic QR symbol`_.
.. _`basic EAN symbol`:
http://zbar.sf.net/test/ean13/9876543210128.png
.. _`basic QR symbol`:
http://chart.apis.google.com/chart?cht=qr&chs=512x512&chl=http://zbar.sf.net/iphone
Long Linear Symbols
^^^^^^^^^^^^^^^^^^^
For this example, we will use a relatively `long Code 128 barcode`_.
.. _`long Code 128 barcode`:
http://zbar.sf.net/test/code128/ALPHA.png
While it should be possible to read this symbol with the default settings, you
may notice that it is not very reliable. You will have to stretch the symbol
across the entire screen, and even then the default settings will only give
you about 1.6 pixels per module, well below the ideal target of 3. To improve
these results, we want to maximize scanning resolution for the long image
axis.
1. Disable the default zoom/crop - zoom all the way out by hitting "Scan" and
pinching the preview; the frame rate immediately drops to 8fps / 4.8fps.
We should compensate for this reduction in the frame rate:
2. Crop the image to a long, skinny rectangle - set the
:member:`~ZBarReaderViewController::scanCrop` setting to
``{{0, 0.3}, {1, 0.4}}``; The frame rate jumps up to 18fps / 8.7fps.
3. Disable scans across the short image axis - set the ``CFG_X_DENSITY``
setting to 0. The frame rate goes all the way to 30fps / 13fps.
Since we have plenty of margin with the frame rate, we can minimize the total
decode latency by performing more scan passes through the symbol:
4. Increase the scan density - set the ``CFG_Y_DENSITY`` setting to 1 (13.5fps
/ 5fps) or 2 (24fps / 9fps).
You should now be able to quickly and reliably decode long linear symbols.
If have a newer device, you may also try increasing the resolution to support
even longer symbols. You may have to compensate elsewhere to bring the frame
rate back to a reasonable level.
High Density QR Symbols
^^^^^^^^^^^^^^^^^^^^^^^
For this example we will use a `version 29 QR Code symbol`_.
.. _`version 29 QR Code symbol`:
http://www.qrcomic.com/images/5.png
In this case we still want to maximize the resolution, but we also need to
increase the scan density to reliably pick up the small finder patterns:
1. Maximize scan density in both directions - set the ``CFG_X_DENSITY`` and
``CFG_Y_DENSITY`` settings both to 1. You should be able to scan the symbol
now, although the frame rate drops to 4.5fps / 1fps
2. Disable the default zoom/crop - zoom all the way out by hitting "Scan" and
pinching the preview; the frame rate drops further to 3fps / 0.7fps
We can compensate somewhat for the reduced frame rate:
3. Crop the image to a square - set ``scanCrop`` to ``{{0.125, 0}, {.75, 1}}``.
This boosts the frame rate slightly to 3.7fps / 0.75fps.
4. Disable linear symbologies - set the symbologies such that only QR Code is
enabled (4fps / 1fps)
Even though the frame rate is still pretty bad, the QR recognition latency
should be acceptable.
If have an iPhone 4, you may also try increasing the resolution to support
even denser QR symbols. You may have to compensate elsewhere to bring the
frame rate back to a reasonable level.
Small DataBar Symbols
^^^^^^^^^^^^^^^^^^^^^
For this example we will use a `DataBar symbol`_ printed with a small feature
size, typical of the stickers used to tag produce. Scale it when printing
such that the printed dimensions are about 1cm square. This symbol should
scan with the default settings, but we will attempt to optimize the scan
latency for this case.
.. _`DataBar symbol`:
http://zbar.sf.net/test/databar/0109876543210128-so.png
As well as high barcode resolution, we also want high density passes in both
directions to minimize sensitivity to rotation:
1. Maximize scan density in both directions - set the ``CFG_X_DENSITY`` and
``CFG_Y_DENSITY`` settings both to 1. The frame rate drops to 4.5fps /
3fps.
Compensate for the reduction in frame rate by zooming in on the small symbol,
which crops the scanned image. Zooming also helps the user see the small
barcode:
2. Zoom all the way in - hit "Scan" and un-pinch the preview. The frame rate
recovers to 11fps / 6.2fps.
3. Crop the image to a square - set ``scanCrop`` to ``{{0.125, 0}, {0.75, 1}}``
(14fps / 7.5fps)
4. Disable all symbologies except DataBar and DataBar Expanded (14.5fps / 9fps)
The reader should now be very sensitive to DataBar, even when scanned at an
angle.

104
iphone/doc/picker.rst Normal file
View File

@ -0,0 +1,104 @@
Scanning a User-Selected Image
==============================
Some applications may need the full resolution offered by camera snapshots, or
need to scan an image or document from the user's photo library. In these
cases you use a :class:`ZBarReaderController`. This reader is a *subclass* of
:class:`UIImagePickerController`, and you use it the same way. See the
documentation for :class:`UIImagePickerController` for more detais.
1. Create the reader.
This is as simple as creating a new :class:`ZBarReaderController`::
ZBarReaderController *reader = [[ZBarReaderController alloc] init];
2. Setup a delegate to receive the results.
The delegate should implement the :class:`ZBarReaderDelegate` protocol,
which inherits from :class:`UIImagePickerControllerDelegate`::
reader.readerDelegate = self;
3. Configure the reader.
You will need to set the :member:`~ZBarReaderController::sourceType`
appropriately. Aside from the properties of the reader itself, you can
configure the decoder via the :member:`~ZBarReaderController::scanner`
property::
if([ZBarReaderController isSourceTypeAvailable:
UIImagePickerControllerSourceTypeCamera])
reader.sourceType = UIImagePickerControllerSourceTypeCamera;
[reader.scanner setSymbology: ZBAR_I25
config: ZBAR_CFG_ENABLE
to: 0];
See :doc:`custom` and :doc:`optimizing` for more details.
4. Present the reader to the user.
As the reader is a UIImagePickerController, it must be presented modally::
[self presentModalViewController: reader
animated: YES];
5. Process the results.
The controller will call the
``imagePickerController:didFinishPickingMediaWithInfo:`` method of
your delegate for a successful decode (NB *not* every time the user takes a
picture or selects an image). The barcode data can be obtained using the
:c:data:`ZBarReaderControllerResults` key of the info dictionary. This key
will return "something enumerable"; keep in mind that there may be multiple
results. You may also retrieve the corresponding image with
:c:data:`UIImagePickerControllerOriginalImage` as usual::
- (void) imagePickerController: (UIImagePickerController*) reader
didFinishPickingMediaWithInfo: (NSDictionary*) info
{
id<NSFastEnumeration> results =
[info objectForKey: ZBarReaderControllerResults];
UIImage *image =
[info objectForKey: UIImagePickerControllerOriginalImage];
...
The ``reader`` parameter will be the actual :class:`ZBarReaderController`
(again, a subclass :class:`UIImagePickerController`).
.. note::
The delegate method should dismiss the reader and return as soon as
possible; any processing of the results should be deferred until later,
otherwise the user will experience unacceptable latency between the
actual scan completion and the visual interface feedback.
6. Dismiss the reader.
Once you have the results you should dismiss the reader::
[reader dismissModalViewControllerAnimated: YES];
.. warning::
It is very important to dismiss from the *reader* (not the presenting
controller) to avoid corrupting the interface.
Handling Failure
----------------
It is always possible the user selects/takes an image that does not contain
barcodes, or that the image quality is not sufficient for the ZBar library to
scan successfully.
In this case, and if :member:`~ZBarReaderController::showsHelpOnFail` is
``YES``, the integrated help controller will automatically be displayed with
reason set to ``"FAIL"``.
Your delegate may also choose to implement the optional
``readerControllerDidFailToRead:withRetry:`` method to explicitly handle
failures. If the ``retry`` parameter is ``NO``, you *must* dismiss the reader
before returning, otherwise you may continue and allow the user to retry the
operation. Note that, if it is enabled, the integrated help will be displayed
when this delegate method is invoked.

Some files were not shown because too many files have changed in this diff Show More