How to Test Document Scanning Apps with Custom Images Using Apple's Virtual Scanner on macOS

Apple provided a sample project demonstrating how to create a virtual scanner device a long time ago. The last revision was on June 12, 2012. In this article, we will build the sample project using the latest Xcode on macOS Sequoia and use it to test front-end document scanning applications like Image Capture and Dynamic Web TWAIN online demo.

What you’ll build: A macOS virtual scanner device (built from Apple’s archived ICA sample code) that feeds custom TIFF images into any ICA-compatible scanning app — including Image Capture and Dynamic Web TWAIN — without requiring physical hardware.

Key Takeaways

  • Apple’s VirtualScanner sample (last revised June 2012) compiles and runs on macOS Sequoia with a single macro fix for the deprecated Carbon require_action function.
  • Replacing the bundled test.tiff with your own image lets you feed any custom document into ICA-compatible scanning apps — eliminating the need for a physical scanner during development and QA.
  • The virtual scanner integrates with Dynamic Web TWAIN out of the box; however, each session supports only one scan before _ICD_ScannerCloseDevice terminates the device.
  • This workflow is the most practical approach for automated SDK integration testing and CI pipelines where scanner hardware is unavailable.

Common Developer Questions

  • How do I use a virtual scanner to test document scanning apps on macOS without hardware?
  • How do I fix the “Call to undeclared function ‘require_action’” build error in Apple’s VirtualScanner sample?
  • Can I use Apple’s virtual scanner with Dynamic Web TWAIN or other ICA-compatible document scanning SDKs?

macOS Virtual Scanner Demo Video

Prerequisites

Step 1: Build the macOS Virtual Scanner from Source

  1. Unzip the sample project and open it in Xcode.
  2. Build the source code. You will encounter the following error:

     Call to undeclared function 'require_action'; ISO C99 and later do not support implicit function declarations
    

    Call to undeclared function 'require_action'

    This error occurs because the require_action macro is defined in the Carbon framework, which has been deprecated. To fix the issue, define the macro in both VirtualScanner.m and EntryPoints.m:

     #define require_action(condition, exceptionLabel, action) \
         do { \
             if ( __builtin_expect(!(condition), 0) ) { \
                 action; \
                 goto exceptionLabel; \
             } \
         } while(0)
    
  3. The project includes a test.tiff file as the input source. Replace it with your own image.

    test.tiff

  4. Build the project to generate VirtualScanner.app. According to Apple’s documentation, the app must be placed in the /Library/Image Capture/Devices/ directory. However, this does not work as expected. To make the virtual scanner appear in the Image Capture app, run the project directly in Xcode instead.

    VirtualScanner.app in Image Capture

Step 2: Test the Virtual Scanner with Image Capture and Dynamic Web TWAIN

Common Issues & Edge Cases

  • Single-scan session limit: The virtual scanner only supports one scan per session with Dynamic Web TWAIN. After the first acquisition, _ICD_ScannerCloseDevice is triggered and the device terminates. Restart the Xcode run target to reset the session.
  • App not appearing in Image Capture: Placing VirtualScanner.app in /Library/Image Capture/Devices/ does not work reliably on recent macOS versions. The scanner only registers correctly when launched directly from Xcode via Run.
  • require_action compile error on Xcode 14+: The Carbon framework is no longer linked by default. If you see Call to undeclared function 'require_action', add the macro definition to both VirtualScanner.m and EntryPoints.m as shown in Step 1 above.

Source Code

https://github.com/yushulx/virtual-scanner/tree/main/macos