Enable camera support in only 3 lines of code

Somehow, I found myself having to revisit camera support in Business Central. Compared to a few year ago, everything can be done in a few lines of code. Check out the video:

https://youtu.be/PxJvQvK4v4U

In this video, Erik demonstrates how easy it is to enable camera support in Business Central using just three lines of AL code. He compares two approaches — the Page-based camera and the Codeunit-based camera — and explains why the Codeunit approach is more reliable, particularly on Android devices.

Two Ways to Use the Camera in Business Central

Business Central provides two different ways to access the device camera:

  1. Page-based approach — Using Page Camera
  2. Codeunit-based approach — Using Codeunit Camera

Erik discovered while updating one of his apps that the Page version does not work reliably on Android devices, even though it works fine on iPhone. The Codeunit version, on the other hand, is slicker, slimmer, and more reliable across platforms. This makes it the recommended approach.

The Codeunit Camera API

The Codeunit Camera has a remarkably simple API with just two key methods:

  • IsAvailable() — Returns a Boolean indicating whether a camera is available on the device.
  • GetPicture(InStream, Text) — Takes a photo using the camera. It populates an InStream with the image data and a Text variable with the file name. Returns a Boolean indicating success.

A Quick Tangent: Running a Codeunit with No OnRun Trigger

Erik noticed that IntelliSense suggests Camera.Run() as an option. Out of curiosity, he tested what happens when you run a codeunit that has no OnRun trigger. The answer? Nothing. It’s valid code, but it doesn’t do anything because there’s no OnRun trigger defined on the Camera codeunit.

The Three Lines of Camera Code

The core logic boils down to three essential operations:

  1. Check if a camera is availableCamera.IsAvailable()
  2. Take the photoCamera.GetPicture(InS, FileName)
  3. Import the photo into your record — Copy the stream data into a Blob field

A Quick Refresher on Streams

Erik offers his classic streams explanation: an InStream is something you read from, and an OutStream is something you write to. The stream is connected to some data — if you connect an InStream to data, you can read the data out; if you connect an OutStream to data, you can put data in. The directions can feel confusing, but the key concept is that the Codeunit stores the photo internally, and GetPicture connects your InStream to that stored photo data so you can read it out.

The Source Code

The extension uses a simple table to store photos:

table 50108 photo
{
    fields
    {
        field(1; P; Code[20])
        {

        }
        field(2; Picture; Blob)
        {
            Subtype = Bitmap;
        }
    }
    keys
    {
        key(PK; P) { }
    }
}

The page includes both approaches as separate actions so you can compare them. Here’s the recommended Codeunit-based approach:

action(test)
{
    caption = 'Clicky Codeunit';
    ApplicationArea = all;
    Promoted = true;
    PromotedCategory = Process;
    PromotedOnly = true;
    trigger OnAction()
    var
        Camera: Codeunit Camera;
        InS: InStream;
        OutS: OutStream;
        FileName: Text;
    begin
        if Camera.IsAvailable() then begin
            if Camera.GetPicture(InS, FileName) then begin
                Rec.Picture.CreateOutStream(OutS);
                CopyStream(OutS, InS);
                Rec.Modify();
            end;
        end;
    end;
}

The flow is straightforward: check if the camera is available, take the picture (which populates the InStream and FileName), then create an OutStream on the Blob field and copy the photo data from the InStream into it.

The Page-Based Approach (For Comparison)

For reference, here’s the Page-based approach that Erik moved away from. Notice how much more verbose it is:

action(test2)
{
    caption = 'Clicky';
    ApplicationArea = all;
    Promoted = true;
    PromotedCategory = Process;
    PromotedOnly = true;
    trigger OnAction()
    var
        Camera: Page Camera;
        InS: InStream;
        OutS: OutStream;
        FileName: Text;
    begin
        if Camera.IsAvailable() then begin
            Camera.SetAllowEdit(true);
            Camera.SetEncodingType("IMage Encoding"::PNG);
            Camera.SetQuality(10);
            Camera.RunModal();
            if Camera.HasPicture() then begin
                Camera.GetPicture(InS);
                Rec.Picture.CreateOutStream(OutS);
                CopyStream(OutS, InS);
                Rec.Modify();
            end;
        end;
    end;
}

The Page version requires additional configuration calls (SetAllowEdit, SetEncodingType, SetQuality), uses RunModal() to open the camera, and then checks HasPicture() before retrieving the image. While it offers more configuration options, it comes with the Android compatibility issue Erik encountered.

A Note About Debugging

Erik points out a known quirk in Business Central: when running under the debugger, the OnOpenPage trigger can fire multiple times, causing the camera to activate repeatedly. He recommends running without the debugger (Ctrl+F5 instead of F5) when testing camera functionality to avoid this behavior.

Running Without HTTPS

Erik also mentions that while he was running on a non-encrypted (HTTP) browser connection during the demo, you can configure your browser to allow hardware access (like the camera) on specific sites even without HTTPS. In production, you’d typically be running over HTTPS where camera permissions work by default.

Summary

If you need camera support in your Business Central app, the Codeunit-based approach is the way to go. It’s simpler, more reliable across platforms (especially Android), and really does come down to three essential operations:

  1. Check availability: Camera.IsAvailable()
  2. Take the photo: Camera.GetPicture(InS, FileName)
  3. Store the photo: CopyStream(OutS, InS) into your Blob field

This is particularly useful if your users work with the Business Central phone app or access Business Central through a mobile browser, enabling them to capture photos directly into your application’s data.