DigitaScript: A Scripting Language for Digital Cameras

Dr. Dobb's Journal January 2001

Extending the functionality of digital cameras

By Rich Robinson

Rich, who works at FlashPoint Technologies, has more than five years experience with scripting and automation languages. He can be contacted at rnr@flashpoint.com.
File I/O Commands

Consumers bought more than 8 million point-and-shoot digital cameras in 2000 and the market is expected to grow to more than 33 million by 2004. One thing they all have in common is (like computers) an operating environment (OE) and development tools. The article "The Digita OS: An Extensible Imaging Platform," by Carlos E. Vidales and Eugene M. Farrelly (DDJ, December 2000) examined the Digita operating environment from FlashPoint (the company I work for). In this article, I'll follow up by discussing DigitaScript, a built-in scripting language that provides user-level access to sophisticated camera controls and image and information flow.

Although DigitaScript can set simple camera parameters such as shutter speed and flash settings, it can also manage databases of information, tell photographers which picture to take next, build web pages, extend the user interface, and communicate with external devices such as barcode readers. It does this with simple text files that are no more difficult to understand than HTML. And it does everything right inside the camera.

You write DigitaScripts in simple ASCII text, give them an 8-character name and .CSM file extension, and store them on standard CompactFlash memory cards in the camera. Once the CompactFlash is inserted into the camera, the script is automatically loaded into RAM and interpreted by the Digita OE. The OE then controls the camera functions as directed by the script.

Every image created by a Digita-enabled camera contains extensive information (metadata) about the photograph. DigitaScript can retrieve, interpret, and act upon information supplied by a data text file, external sources, and data from the image metadata. There are more than 100 metainformation tags associated with an image, and more than 30 can be user defined and used to store information after the image is captured. You can tag an image with information that originated in employee databases, inventory control systems, or GPS receivers. You can even tag an image with voice annotation via the camera UI. In short, you can program a camera for any task, from taking better pictures of a soccer game to managing a complex workflow for insurance adjusters.

DigitaScript Scripts

In a DigitaScript script, comment lines are denoted by the pound sign "#" for single lines. Asterisks and backslashes "/*" and "*/" are used to denote multiline comments. Excluding comment lines, all DigitaScripts begin with four important statements:

Since the space for text on the camera LCD is limited, labels, menus, and messages must be short. The amount of space available also varies from camera to camera. Text strings may be truncated or extend off the screen if they're too long.

All DigitaScripts end with exitscript (see Listing One) or call another script that ends with exitscript. There are two exceptions: When telling the camera to power down (SetPowerMode()) or running an application (RunApp()), exitscript is not used.

You can make a script run automatically at camera power up by simply changing the name of your script to: "STARTUP.CSM." This is useful in vertical markets and specialized situations. For instance, if you want to use the camera in a workflow situation where users have no training, a startup script can tell users what to do. If you're in a particular picture-taking situation and want the camera settings custom set when you turn on the camera, a startup script is the way to go.

Only one startup script at a time is supported. But scripts can run other scripts, so you can use a startup script to allow the user to pick the next script to run. Startup scripts should include some wait times at the start and end of the code. Camera errors can occur if the boot process has not completed when script commands are issued.

DigitaScript supports seven internal data types:

The variable names used for these data types should not exceed 31 characters. The style of variable name that I prefer always starts with the character that represents the data type. All the examples shown in this article use this naming convention. Declare statements are formatted as follows:

declare u: uMyVariable

DigitaScript can read/write text files in the camera and has the capability to read/write data within the image file itself. Combining these features turns your camera into a real data collection tool. This creates powerful opportunities for use in vertical markets, but also has broad appeal to nonprofessionals.

The DigitaScript read/write feature extends the capability and functionality of the camera. Any text file that can be used or interpreted by other applications, such as HTML, Visual Basic, tab-delimited data files, or XML can be created within the camera.

A good example would be a home inventory system like that at http://www.digitaphoto.com/insurance/. How would a home inventory script work? First you would need to fill out a spreadsheet or database. Sample fields might include item name, serial number, estimated value, and so forth. Then you would export the information in a tab- or comma-delimited text file. The file would then be placed on your camera's memory card, along with the proper scripts, and you're ready to go.

The camera tells users which pictures to take. After the pictures are taken, a web page is automatically generated for each image in the camera, with the proper information assigned to each item. An index web page would also be generated for all items photographed. The pictures and HTML can then be copied off of the memory card and onto your hard drive or the Web.

Similar code could be used for a child ID program, online auctions, a corporate pictures page for employees, appraisals, e-commerce, or any of a number of other possibilities. The list can be as long as you like. The information embedded in the image keeps the data association correct.

In-Camera Text Files

All versions of DigitaScript allow creation of (and writing to) .txt files. DigitaScript Version 1.5 or greater supports both reading and writing of text files on the camera's memory card.

The required commands for this functionality are: FileOpen(), FileClose(), Write(), WriteLine(), SetDelimiter(), Read(), and ReadLine(). The accompanying text box entitled "File I/O Commands" explains these commands and their uses.

Titles and User Input

There are times when it is necessary for users to select a choice, change a value, or otherwise communicate with the running script. As Listing Two illustrates, scripts can create option menus through the use of the SetOption() and GetOption() commands.

In this listing, three items or choices would be shown for the three options: Shoot Pictures, Build HTML, or Exit Script. The first argument to the SetOption() function is an identifier, and can be any number between 0 and 0xFFFFFFFF. GetOption() sets its argument to the number of the choice that was picked. If statements can be used for branching, as in the listing, or the selected variable can be used to set values in your code directly.

Another useful command when creating option menus for users is the SetTitle() command. By default, the label used to launch a script becomes the screen heading when subsequent screens are displayed. SetTitle() lets you change the title at any time. With Listing Two, you would see "What Now?" on top of the screen.

Guided Capture

DigitaScript can guide users through the capture process. You can display messages telling users what to do. Listing Three, for instance, places the camera in live view (LCD on), with text information at the top of the screen.

Markers are used with goto statements. Markers are followed by a colon, as in "SHOOT_HALLWAY:". At times, the script can get ahead of the camera, so wait statements are used. Wait statements are also used to give users time to read any displayed messages. The Exit button is enabled when in any wait statement, providing a convenient exit path for users anywhere in the script.

The ability to check a command's status is also important. DigitaScript reports any errors when checking status on a command. Successful execution returns a zero. If you do run into scripting problems, status checking is essential. WaitForShutter() is one of the commands I've found that should be checked, as in Listing Three. In Listing Three, if iStatus does not return success for the WaitForShutter(), it will repeat the command until 0 is returned. Then SetCaptureMode() sets the capture mode to still. SetCaptureMode() can set the mode to either still, group, or time-lapse. StartCapture() shoots the picture. The StartCapture() command can also be used to set a group folder name or the time-lapse parameters, total images, time between images, and image resolution. The EndCapture() statement completes the picture-taking process.

Camera Parameters

One of the more straightforward functions of the language is controlling and retrieving camera settings. This is accomplished with SetCameraState() and GetCameraState(). Camera parameters and file tags are represented by 4-character codes. They are specified using a string variable or as shown in Listing Four. You can turn the flash on or off, switch from auto focus to manual focus, set the zoom position, set the image stamp text and its location, or select a logo image stamp. The long list of features includes anywhere from 50 to over 100 internal parameters, depending on the camera model. SetCameraState() settings are temporary, good until power-down. Use SetCameraDefault() to set values that are kept through a power cycle. Note that some parameters' default values can't be set.

File Tags

There are two types of file tags: standard (read only) and user (read/write). The data contained in these tags is part of the image file. Standard tags are written to the image file when it is created in the camera at the time of capture. User-writable tag names begin with "u."

The camera must complete image processing before DigitaScript can read/write to file tags. To see whether processing is complete, use GetCameraStatus() to check ipip (the image processing flag).

One user tag is automatically written to the image file at time of capture, the ucpt (user copyright) tag. Its value can be set in the camera EPROM with SetCameraState() or SetCameraDefault(). (This is a DigitaScript Version 1.5 feature.)

The command GetMarkedImage() (see Listing Five) retrieves the file ID for any marked image. All Digita-enabled cameras have the ability in the UI or script language to mark one or more images. If no image has been marked, the last image taken or viewed is considered marked. If more than one image is marked, GetMarkedImageCount() returns the total count. You can use a loop to step through the images, but note that image ID values start at 0, so you'll need to subtract 1 from the total count.

File tag information (the metadata mentioned earlier), is used in numerous ways. It provides technical information for the photographer such as camera settings, camera model and serial number, date and time when taken, image size, zoom position, and shutter speed. You can display the information on the camera screen, use the data in a web page or report, or tie the data in the image to an external database.

Phone List

DigitaScript's file capabilities also allow for numerous other applications, some not necessarily dealing with images at all. Listing Six lets you put your own searchable phone list in the camera. All that's required is a tab-delimited file with four fields per line: Name, E-mail, Phone, and Cell Phone. The last line in the data file should be the word "end."

This code introduces two more commands, GetString() and FindString(). GetString() is used to get input directly from users. This command takes users to the camera's standard input screen and displays your prompt. The camera's four-way controller can then be used to select up to 31 characters of text input.

The FindString() command has four arguments, sSource, uStart, sFind, and iLocation. These are the string/source being searched (s or t variables), the start point in the source, the find string, and the location/character position (i variable). If the search string is not found, "-1" is returned.

Now you have an overview of some of the cool things that DigitaScript can do, from the functional to the fun. Extend your camera's capabilities by downloading DigitaScripts from Script Central online at http://www.digitaphoto.com/digita_script/.

DigitaScript Applications

Companies such as Kaidan, Opsis, Ipix, Red Hen Systems, ActivePhoto, and Kodak, to name a few, use DigitaScript to deliver imaging solutions. For example, DigitaScript commands drive Kaidan's AutoPan Motorized VR Tripod Head to rotate and capture pictures automatically (http://www.kaidan.com/products/autopan.html). DigitaScript is also used in the iRemote and PhotoGPS systems (http://www.digital-opsis.com/). A complete article about GPS solutions using Digita can be found at http://www.digitaphoto.com/gps/. For more intensive projects, in-camera compiled applications can be written with the help of the robust Digita Application SDK.

As with all electronic devices, digital cameras are delivering more horsepower for less money every day. This is especially noticeable in portable communications; the first wireless photography solutions are just coming to market now. The power and simplicity of DigitaScript gives you an extensive toolkit for configuring these devices, controlling user experiences, and managing the flow of information they collect. It is an easily accessible pathway to the marriage of instant, anytime, anywhere communications and rich, expressive photography.

DDJ

Listing One

# Demo script - Display text & exit
name "Demo script 1"
mode 0
menu "Demo Script"
label "Display Exit"

DisplayLine( "Script will exit in 4 seconds" )
Wait(4000)
exitscript

Back to Article

Listing Two

# Demo - User option choice
declare u: uOptionChoice

SetTitle( "What Now?" )
SetOption( 1,"Shoot Pictures" )
SetOption( 2,"Build HTML" )
SetOption( 86,"Exit Script" )
GetOption( uOptionChoice )
Wait(100)
if uOptionChoice == 2
  goto BUILD_HTML
end
if uOptionChoice == 86
  exitscript
end
# shoot pictures code continues here
# the marker BUILD_HTML: occurs later in the script

Back to Article

Listing Three

# Demo - Guided capture with status check
SHOOT_HALLWAY:

iStatus = WaitForShutter( "Shoot Hallway" )
if iStatus == 0
  SetCaptureMode( still )
  StartCapture()
  Wait(250)
  EndCapture()
end
if iStatus != 0
  goto SHOOT_HALLWAY
end

Back to Article

Listing Four

# Set Camera parameters
# fmtd = Focus Method, 2 = Center Spot
SetCameraState ( "fmtd", 2 )
# zpos = Zoom position 150 = 1.5x
SetCameraState ( "zpos", 150 )
# wmod = White balance, 6 = Fluorescent
SetCameraState ( "wmod", 6 )

# Get Camera parameters (returned values)
# mtdy = Self timer delay, Seconds
GetCameraState ( "mtdy", uDelaySec )
# bttc = Battery Sleep Timeout, Seconds
GetCameraState ( "bttc", uBST )
DisplayLine( "Battery sleep timeout: ", uBST, " sec." )
DisplayLine( "Self timer delay: ", uDelaySec, " sec." )
Wait(4000)

Back to Article

Listing Five

GetMarkedImage( 0, sImagePath, nFileName )
# ucnt - Write User Caption tag
SetUserFileTag ( sImagePath, nFileName, "ucnt", "My Caption" )

# ptid - Product ID/Name
GetFileTag ( sImagePath, nFileName, "ptid", sProdID )
# date - Capture date of image
GetFileTag ( sImagePath, nFileName, "date", bCaptDate )
# shut - Shutter speed
GetFileTag ( sImagePath, nFileName, "shut", uShutSpeed )
ucnt - User Caption tag
GetFileTag ( sImagePath, nFileName, "ucnt", sParamVal )

Back to Article

Listing Six

# Complete script for PhoneList v1.0
# Last line in address file should be "end"
# Data sequence tab separated, Name,Email,Phone,Cell Phone
# Data file name "phonelst.txt" in system folder
name "Phone Number List"
mode 0                  # Capture Mode
menu "My INFO:"
label "Phone List"

declare t: tSearchText,tName,tEmail,tPhone,tCellPh
declare s: sSearchText
declare i: iStatus,iLocation
declare u: uPhFileID,uOptionChoice

iStatus = FileOpen( 2, "/System/phonelst.txt" ,2 ,uPhFileID )
if iStatus != 0
  DisplayLine( "FAILED - FileOpen Read - phonelst.txt" )
  DisplayLine( "File is missing" )
  Wait(4000)
  exitscript
end

SetTitle( "Search for?" )
GetString( "Enter text, press continue:",sSearchText )
Wait(10)
DisplayClear()
DisplayLine( "Searching..." )

FIND_COUNTER:
SetDelimiter(tab)
ReadLine( uPhFileID,tName,tEmail,tPhone,tCellPh )
tSearchText = tName+tEmail+tPhone+tCellPh
FindString( tSearchText,0,sSearchText,iLocation )

if tName == "end"
  DisplayClear()
  DisplayLine( "Text not found." )
  DisplayLine( "Search is case sensitive." )
  DisplayLine( "Script will exit." )
  Wait(3000)
  exitscript
end

if iLocation != -1
  goto FOUND_NAME
end

if iLocation == -1
  goto FIND_COUNTER
end

FOUND_NAME:
SetTitle( tName )
SetOption( 0,"This is it" )
SetOption( 1,"Continue search" )
SetOption( 86,"Exit Script" )
GetOption( uOptionChoice )
if uOptionChoice == 1
  Wait(10)
  DisplayClear()
  DisplayLine( "Searching..." )
  goto FIND_COUNTER
end
if uOptionChoice == 86
        exitscript
end

INFO_DISPLAY_LOOP:
DisplayClear()
DisplayLine( tName )
DisplayLine( tEmail )
DisplayLine( tPhone )
DisplayLine( tCellPh )
Wait(15000)
exitscript




Back to Article