ScannerMApp: a QR/barcode scanner app with Delphi, ZXing and TFrameStand

It is plenty out there of barcode/QR code scanner apps (both on Android Play Store and Apple AppStore [and iOS 11 include native code scanner in the camera app]) so it may seem there is no need to build a new one but this is not true!

In this blog post I will describe how I built a barcode scanner app (ScannerMApp, currently available in a beta stage on the Play Store) in Delphi using the Edward Spelt’s Delphi port of the ZXing library and my TFrameStand component.

The project only depends on Delphi (10.2 Tokyo used) and two OSS libraries: ZXing and TFrameStand. Full source code of ScannerMApp is available on my GitHub.com repository.

ScannerMApp icon

Video demo

Sometimes, a video is better than a thousand words: here it is a 45 seconds video showcasing ScannerMApp 🙂

 


 

 

Introduction

QR codes (barcodes, in general) are really handy when you need to join the physical world with the digital one, simply put a QR code on an item or in a physical place and that item/place is now digitally tagged (and you can take advantage of this in your applications).

While preparing material for the last Delphi mobile training course I gave, I received questions about building a solution to read barcodes / QR codes in a Delphi mobile app. I already covered this argument on my blog, at XE5 time and later with XE7, but with a different approach: launch a third-party barcode scanner app and get results through clipboards or Android intent infrastructure.

This time I tried to have more control and decided to integrate a library for QR code recognition directly into my FMX app. This approach has some advantages like:

  • it does not create a dependency with a third party app (or/and the way to communicate with it);
  • it gives you full control on all details of the scanning phase: you can provide a bitmap to the library and ask for a search of desired code types so you may want to get a frame from a camera (deciding resolution if you care), add some pre-processing if needed and get some additional informations about the result, like the exact position of the found code in the bitmap;
  • if the barcode recognition library is written 100% Delphi code, you achieve a great portability of your app through different platforms (Android, iOS, Windows, Mac OS X and Linux!)

So I decided to build this FMX application trying to provide a tangible example about how to structure a simple Delphi mobile app that access sensors (camera can be considered a sensor), stores values and present them to the user through a minimal UI.

Scanning barcodes

The ZXing project is the most popular open source barcode scanning library in Java and has been ported to different languages (C++, .Net C#, php, Objective-C, python, JavaScript and … Delphi! 🙂 ).

Thanks to Edward Spelt and his Delphi library (that I would suggest to be added here) we all can benefit and easily build barcode-enabled multi-platform applications with Delphi!

The library is very easy to use, fast, has good support to all major barcode formats and has been recently updated with a farther performance improvement tied to inverted barcode recognition (now optional, so you can save time if you don’t need to read inverted barcodes).

I want to thank Edward for the kind suggestions (and corrections to my code) he gave me during the development of this app.

ZXing.Delphi on GitHub.com

You can obviously have a look to ZXing.Delphi demos and to the source code of my ScannerMApp and see all the details on how the library works and has been used.

For the ScannerMApp, I decided to implement two use cases:

  1. start the device camera (using a low resolution setting), grab each available frame but scan only each X milliseconds (currently X=133, to give something like 7 attempts per second);
  2. pick a picture from the library (or filesystem on Desktop platforms) and scan once (generally sufficient since there is no focusing problems and of course no targeting is possible).

The app structure

I tend to structure my Delphi mobile apps using datamodules, a single main form and several frames. Using TFrameStand is easy to orchestrate how the frames get shown to compose the user experience.

Here is a simple diagram of ScannerMApp:

ScannerMApp structure

All the important code is in the main datamodule (MainDM) including the TCameraComponent used to grab frames from the device camera, the TFDMemTable used as storage for result data and all the ZXing.Delphi related code.

Each frame is used to present a different piece of UI to the user, reflecting the app status and data available:

  • TScanningFrame is responsible to help the user acquire the barcode by painting the camera’s frames on a TRectangle (faster than a TImage) and hosts an informative label about current camera resolution (and FPS even if it seems to be hardcoded in Android) and a button to toggle the torch mode (where available) that may help when there is no sufficient light in the room; during the scanning, you may see some TRectangle(s) being drawn over the camera’s frame, to indicate the ZXing.Delphi library detected something possibly being a barcode there.
  • TDataFrame has a TListView with DynamicAppearance and is used to present to the user the so far scanned barcodes, including details per each item like a thumbnail, the barcode format, the content and a counter of how many times that specific barcode has been scanned (since the start of the app); clicking on an item will lead to the details (see next point in this list);
  • TScanResultFrame is used to present the user the successfully scanned barcode informations like format, date of (first) acquisition, a picture of the frame with some markers indicating the barcode position and a couple of actions to let the user delete the current item or share the content of the barcode through the system’s ShareSheet;
  • TInfoFrame (not listed in the above diagram) is used to show a simple credits layout about the app and libraries used.

On the MainForm you can see the TFrameStand instance that will orchestrate the UI through all the app.

I decided to take advantage of the built-in System.Messaging publish/subscribe mechanism using the default TMessageManager to send and receive messages through all the app. This way, the dependencies across the modules (forms, datamodule, frames) of the app are minimal (many knows the MainDM, the MainForm knows most of the frames but no crossed dependecies) and code can be properly separated (no UI code in the datamodule, no application code in the UI frames). You can see, in the above diagram, who is publishing messages and who is subscribed to them by looking at the small mail icon (green = subscribed, red = publish). As you can see in the code of Data.Main.pas and here below, a  bunch of custom messages have been defined and used across the app:

 TScanningMessage = TMessage<Boolean>;
 TScanResultMessage = TObjectMessage<TScanResult>;
 TScanPointMessage = TMessage<TPointF>;
 TScanSettingMessage = TMessage<TVideoCaptureSetting>;
 TTorchModeMessage = TMessage<Boolean>;
 TCameraBufferMessage = TMessage<TBitmap>;
 THardwareBackMessage = TMessage<Integer>;

For example:

  • each time a frame is available from the device camera (see TMainDM.CameraComponent1SampleBufferReady), a TCameraBufferMessage is sent (and the TScanningFrame, subscribed to that message, will receive the bitmap to be shown to the user);
  • each time the ZXing.Delphi library detects a possible result point of a barcode (during scan) a TScanPointMessage is sent (and TScanningFrame will inform the user by drawing a rectangle over the frame);
  • when a barcode is successfully found, the MainDM will send a TScanResultMessage and the MainForm, the MainDM and the TDataFrame will be informed about the newly available result (the MainForm will ensure the user can see the TDataFrame, the MainDM will store the result in the TFDMemTable and the TDataFrame will refresh the ListView).

Technologies

It has been a pleasure to build this app, using a lot of different technologies included in Delphi or available as OpenSource projects.

  • RTL provides (among many other features) the System.Messaging mechanism
  • FMX provides(among many other features) easy access to the device camera
  • FireDAC is used to easily store results (using a memory table and including bitmaps)
  • LiveBindings are used to bind the memory table to the TListview on the TDataFrame
  • Parallel programming library is used to perform barcode scanning in the background of the application, ensuring a great user experience
  • ZXing.Delphi implements barcode detection and decoding
  • TFrameStand orchestrates the UI, providing visual continuity and nice effects/transitions easily

What’s next and conclusion

As I said, this app was initially built to be shown and explained in a training course of mine (as a proof of concept), then I tried to polish it a bit, improve performance and user experience (thanks again to Edward Spelt for some hints and suggestions) and now I am releasing it as an example for all Delphi developers. Of course it can be greatly improved in some areas and of course it is far from perfect but seems nice so far 😉

There are a few things I’d like to do:

  • register the app for SEND action intent-filter on Android (would make ScannerMApp to show up in the ShareSheet, also from other applications). This is a work in progress but not yet finished.
  • need to test a bit on iOS (if anyone can give feedback it would be great)
  • define a storage strategy (locally save the memory table or send data to a remote server, depending on needs)
  • provide a sound feedback on successful scans
  • filtering desired barcode format (the user may be looking only for QR codes or EAN13… this should improve precision in result acquisition reducing false positives)

I hope you’ll enjoy this example as I do! I think this is a good example how easy it is to build a not-so-trivial mobile app with Delphi (and have it running on multiple platforms!).

Have a nice day and good work!

Andrea

41 thoughts on “ScannerMApp: a QR/barcode scanner app with Delphi, ZXing and TFrameStand

  1. Claudio Piffer says:

    Great article Andrea!!!

  2. Edmilson says:

    Amazing article!

  3. Visli says:

    It can not focus automatically when shooting.

    1. andrea.magni says:

      As I wrote here (https://plus.google.com/+AndreaMagni/posts/M2JpUHYoo7g) it may depend on your camera capability of continuous autofocus mode. Edward told me autofocus may be sufficient but I guess continuous autofocus should be better especially if you are using a smartphone and trying to scan something in your hands…
      Maybe it would be better to have a setting in the app.

  4. Iwan Cahyadi Sugeng says:

    Hi andrea, i’ve been using other barcode reader component for fmx too, i do not know what is the difference, but anyway, the main problems is the TCameraComponent it self is so slow in response, so i have to use the native camera viewer, but it also failed sometimes. So did you experiencing the same problem with the TCameraComponent?

    1. andrea.magni says:

      Hi Iwan, for sure the image acquisition may be optimized. I would like to test a couple of alternatives but performance seems fine to me on a Nexus 5 and 5X phones (also tested on my Nexus 7 tablet).
      I have added the ability to scan a pre-existing image because I knew sometimes the camera app can be far better than grabbing frames with camera component…

  5. Edward says:

    Hi Iwan,

    The TCameraComponent is slow. Especially on Android. Please take a look at the huge camera performance tweak from Erik van Bilsen. See: https://quality.embarcadero.com/browse/RSP-10592

  6. Hi Andrea, first have to say it’s conceptually a great app.
    I immidiatelly testet it on a row of platforms and Here’s my first Feedback:

    I use Berlin(latest) cause of the “OnIdle” Bug with Tokyo

    Android 4.4 works best
    Samsung XCover3 – Has no ConinousAutoFocus -> Exception – can not test.
    iOS 10.3 on iPhone6+ – Lot’s of Exception mainly in the ScanManager. But also i see a memory leak in using the cropped bitmap. You create many instances of ScanManager parallel. I think there are memory leaks in using the class var in ZXing (e.g. Code39Implementaion) Creating more then 1 ScanManager.
    A class Var is a global variable. For every Scanmanager a TCode39Reader is created and a new Class Var instantiated

  7. Deadc0der says:

    Hi Andrea , well your example is great and work perfectly on Delphi 10.2 Tokyo on Android except that the app crashes after few seconds from scanning do u have a patch for this !!!
    thanks in advance

  8. Sete says:

    Same error here. Works fine in Android, but app crashes after a few seconds while scanning in my iPad. I can see the camera for about 5 seconds and then it crashes!

  9. Mohsen Darrehshiri says:

    Hi Andrea, I’m a beginner in Android programming, and when I run your app on my phone, I’ve got a error with a file that does not exist on my computer.
    But the program is build & compiled successfully, but this error appears when run and transferring to my mobile.

    That is about “keystore” file.

    Please help me What should I do?

    Thanks

    1. Deadc0der says:

      Change the configuration from playstore to developement

      1. Andrea Magni says:

        Right! I just pushed an updated dproj file that should solve this from the start.

        Thanks

  10. eka senaputra says:

    I got this error:
    [PAClient Error] Error: E2568 Unable to execute ‘”C:\Program Files (x86)\Java\jdk1.8.0_66\bin\JarSigner.exe” -keystore “C:\Sviluppo\Progetti\keystore_andrea.keystore” -storepass XXXXX -keypass XXXXX -sigalg MD5withRSA -digestalg SHA1 “D:\work\coba\ScannerMApp-master\s2\Android\Release\s1\bin\s1-unsigned.apk” “andreamagni”‘ (Error 1)
    [PAClient Error] Error: E2568 jarsigner error: java.lang.RuntimeException: keystore load: C:\Sviluppo\Progetti\keystore_andrea.keystore (The system cannot find the path specified)

    any help ? thank you

  11. Peter says:

    I miss a component, nou i have lots of files and libs.
    and Several designint error….
    So can you update this product?

    1. Andrea Magni says:

      What component are you missing? TFrameStand? You can download it from https://github.com/andrea-magni/TFrameStand or install it through GetIt Package Manager.
      Let me know…

      1. Peter says:

        TFramestand works,
        Now i got compiler errors , DesignIDE, DesignF, and on

  12. Dirk says:

    Hi,

    nice app and demo!
    I’ve tested on Nokia 6 with Android 8.1.0 with Delphi 10.2.3 and drawing is soo slow and not far from unusable.
    Another test with Delphi.ZXing advanced example is much faster and gives the user a smooth feeling.
    Demo here: https://github.com/Spelt/ZXing.Delphi/tree/v_3.0/AdvancedTestApp

    this is the patch for TCamera component:
    https://quality.embarcadero.com/browse/RSP-10592

    But i had no success, i assume you do a lot creating/copying bitmaps.

    Best
    Dirk

  13. Octave says:

    I had compile your excellente project with Delphi Tokyo 10.2.3 for win32.

    All is OK but when the barcode is scanned, an access violation error on module ScannerMApp appears at the address 007C9679.

    The crash appears just when the badrcode is identified…

    Have you an idea of solution? Is it a problem with the installation of ZXing?

  14. Jimmy Orkin says:

    Andrea, I see differences between your beta app in the Play Store and the app when I build it in Delphi. The Play Store app seems to have a faster frame rate, the camera actually continuously autofocuses and touching the scan entry in the list of scans drills in the scan instead of getting an Access violation.

    Has the play store app been updated that is not reflected in your github project? Or does the Play Store app have any of the Firemonkey camera fixes I have been reading about on the forums?

    Thanks, Jimmy

    1. Ari says:

      HI Jimmy,

      Do you have solved this issue?i have the same problem when build it in delphi.

      Thanks.

  15. Yuskamal says:

    Mr. Andrea, how about Android API 26 compatibility, I try to change the project following Dave’s Article https://www.delphiworlds.com/2018/06/targeting-android-8-and-higher-continued/
    and now I cannot run my project

    thanks, Yuskamal

  16. Hi, Nice and thanks for this free component for Delphi. Can you please.. give sample code which the mobile barcode apps scan and send to Windows Apps (Created Delphi also).

  17. Jerry Martinez says:

    Unable to build your project for Android in Delphi Rio. TFrameStand previously installed from GetIt. I get the following compile error.

    [MSBuild Error] The “GetItCmd” task failed unexpectedly.
    System.NullReferenceException: Object reference not set to an instance of an object.
    at Borland.Build.Tasks.Common.CommandLineTask.Execute()
    at Borland.Build.Tasks.Shared.GetItCmd.Execute()
    at Microsoft.Build.BuildEngine.TaskEngine.ExecuteInstantiatedTask(EngineProxy engineProxy, ItemBucket bucket, TaskExecutionMode howToExecuteTask, ITask task, Boolean& taskResult)

    1. Alfredo says:

      Did you fix this bug?

      1. Aku Adalah says:

        Try this:

        Project > Options > Project Properties > GetIt Dependencies

        uncheck TFrameStand

  18. Alfredo says:

    Same problem as Jerry.

    [MSBuild Error] The “GetItCmd” task failed unexpectedly.
    System.NullReferenceException: Object reference not set to an instance of an object.
    at Borland.Build.Tasks.Common.CommandLineTask.Execute()
    at Borland.Build.Tasks.Shared.GetItCmd.Execute()
    at Microsoft.Build.BuildEngine.TaskEngine.ExecuteInstantiatedTask(EngineProxy engineProxy, ItemBucket bucket, TaskExecutionMode howToExecuteTask, ITask task, Boolean& taskResult)

  19. Trevor Bradley says:

    Hi
    Good example to get to learn how to capture barcodes.
    Only problem I have is that the app sits waiting for camera permisssion in testing on a Sony XZ1, never pops up asking for permissions?
    Probably something I am not doing correctly!
    Thanks
    Trevor

    1. Andrea Magni says:

      ScannerMApp actually needs some love and upgrade to latest Delphi version and latest Android’s Permission system changes.
      Hope to find time and fix it…

  20. Alba Ngalula says:

    ¶the project example of zxing.delphi version 3.0 is not functioned on Delphi XE10.2 Tokyo, there is an error during compilation on android (error of permission)

  21. walid cosmos says:

    mr andrea hello
    i need help for change to front camera
    thank you

  22. Mahdi says:

    Mr Andrea hello
    nice Project
    thank you

  23. Kakek Belia says:

    error IWStandAloneServer not found, where i can found it?

    thank’s Mr.

  24. moko says:

    saya memakai delphi xe5 mohon solusinya,,,
    https://prntscr.com/w6ml5h
    https://prntscr.com/w6ml0m

  25. james cooper says:

    Hi there, is there any way in which i can use this in a delphi multi device application in delphi 10.4? Any information on how to achieve this?

  26. J. Kelly Wilkerson says:

    Andrea, I’m using this in 10.4.2 and have great success on iPhone XR. However, iPhone 11 Pro and iPhone 8 Plus is another story. I have the code configured to use TVideoCaptureQuality.LowQuality, but still get a “Bitmap size too big” error when activating the camera component when approving the permission. Surely the low quality setting should be a low enough resolution to produce a smaller bitmap image, right?

    Here is the code for activating:
    CameraComponent1.Active := false;
    CameraComponent1.Kind := FMX.Media.TCameraKind.BackCamera;
    CameraComponent1.FocusMode := FMX.Media.TFocusMode.ContinuousAutoFocus;
    CameraComponent1.Quality := TVideoCaptureQuality.LowQuality;
    CameraComponent1.Active := true;

    Any ideas would be super helpful.

    Thanks,

    Kelly.

  27. Anang Ganjar says:

    Hi Andrea, Thanks for app,

    for everyone , if you want to run android 9 above and show error dialogs,
    you just need to check secure file sharing in Entitlement List

  28. Hi Andrea,
    Thanks for publishing your ScannerMapp – I learned hugely from (mostly) getting it to work.
    Using Delphi Enterprise 10.4.1 on Windows 10 and a Galaxy A10 with Android OS11, it would run and scan once successfully, but on the second scan it would come up with an Access Violation related to getting image size. Try as I may, I could not trace the reason for the failure.

    After two weeks I gave up and went back to basics by using AdvancedTestApp by Edward Spelt and ZXing where I was able to develop a useable .apk that included sound, front or back camera, and barcode choice, by stitching together anything I could find on the web.

    For me its just a learning experience and will not be used commercially – I am now just a hobbyist after retiring in 2020, but if anyone would like the project code then feel free to get in touch,

    1. Kosuke Kamei says:

      Hi Craig,
      Can I have your code?

    2. Sandro says:

      Hi Craig
      May I take a look at your code?
      Thank you
      Sandro

  29. ivanilson ribeiro says:

    i need to use this sample in Delphi 11.2

Leave a Reply

Your email address will not be published.

This site uses Akismet to reduce spam. Learn how your comment data is processed.