Taking photos

To capture a photo, you need to:

You might also want to:

The Camera libraries don't automatically play audible shutter sounds when a picture is taken or a video is recorded. Camera apps must supply their own sound when a photo is captured or a video recording begins and ends. Although you can choose to not have a shutter sound when taking a picture or a video, you are responsible for ensuring that your app adheres to the local laws of the regions in which you distribute the app. For example, it is illegal to mute or change the shutter sound of a camera app in Japan or South Korea. For more information, see the BlackBerry World Vetting Criteria.

Using the Camera C API, you can also:

  • Take photos in burst mode: Burst mode allows you to take a number of photos in rapid succession.
  • Take photos in HDR mode: High dynamic range (HDR) mode allows you to capture high-quality images by increasing the dynamic range of the images.

Set camera properties

You can set or change many photo properties. For example, you can change the camera's capture resolution, focus mode, and shooting mode.

In the Camera C++ API, all of these properties can be accessed by creating an instance of the CameraSettings object and using it to set the properties of your camera. Your app determines how your users select and set values for the camera's properties. One approach is to let your user select property values from a UI control such as a DropDown list and then apply them with another UI control such as a Button. Another approach is to give the user a menu, such as the Actions bar, to do the same thing. For more information about the Actions bar, see Menus.

Using the Camera C API, you can access advanced camera properties such as aperture, shutter speed, ISO, viewfinder modes, and video properties. Depending on the properties that you want to set, you might need to stop and restart the viewfinder. For more information about each camera property, see camera_api.h.

The following code samples demonstrate how to set the camera's flash mode. You can extend these instructions and techniques to set other camera properties.

First, you set up a CameraSettings object and add it to the Camera control as an attached object. You can use the id to set and apply a new flash mode setting.

// The Camera control
Camera {
    id: qmlCameraObj
    // ...
 
    attachedObjects: [
        // ...
 
        CameraSettings {
            id: camSettings
        }
    ]
 
    // ...
}
                        
                    

To allow your users to choose a flash mode setting and apply it, you can use a DropDown list and a Button. Create a DropDown with the id flashmode_dropdown to display the flash mode options. Use a Button to apply the selected flash mode settings.

// Use a DropDown to select the
// preferred flash mode
DropDown {
    id: flashmode_dropdown
    selectedIndex: 2
    title : "Flash Mode"
    enabled : true
    Option {
        text : "Off"     // Disable flash
    }
    Option {
        text : "On"      // Always use flash
    }
    Option {
        text : "Auto"    // Use flash in low light conditions
    }
    Option {
        text : "Light"   // The light is on for the duration
                         // that the viewfinder is active
    }
}
 
// ...
 
// The CameraSettings object has the id of camSettings.
// The camera id is qmlCameraObj.
// The selected index coincides with the enum's numerical
// value of the listed flash modes.
Button {
    id: btnApplySettings
    onClick: {        
        qmlCameraObj.getSettings(camSettings); 
        camSettings.flashMode = flashmode_dropdown.selectedIndex;
        qmlCameraObj.applySettings(camSettings);
    }
}
                        
                    

Another option for setting the flash mode is to use the Actions bar menu. This option keeps the flash mode settings hidden until the user wants to see them. When the user opens the Actions bar menu and selects a flash mode, the app sets the selected option.

Page {
   // Actions menu
    actions: [
        ActionItem {
            title: "Flash Mode: Off"
            ActionBar.placement: ActionBarPlacement.InOverflow
            onTriggered: {
                qmlCameraObj.getSettings(camSettings);
                camSettings.flashMode = CameraFlashMode.Off;
                qmlCameraObj.applySettings(camSettings);
            }
        },
        ActionItem {
            title: "Flash Mode: On"
            ActionBar.placement: ActionBarPlacement.InOverflow
            onTriggered: {
                qmlCameraObj.getSettings(camSettings);
                camSettings.flashMode = CameraFlashMode.On;
                qmlCameraObj.applySettings(camSettings);
            }
        },
        ActionItem {
            title: "Flash Mode: Auto"
            ActionBar.placement: ActionBarPlacement.InOverflow
            onTriggered: {
                qmlCameraObj.getSettings(camSettings);
                camSettings.flashMode = CameraFlashMode.Auto;
                qmlCameraObj.applySettings(camSettings);
            }
        },
        ActionItem {
            title: "Flash Mode: Light"
            ActionBar.placement: ActionBarPlacement.InOverflow
            onTriggered: {
                qmlCameraObj.getSettings(camSettings);
                camSettings.flashMode = CameraFlashMode.Light;
                qmlCameraObj.applySettings(camSettings);
            }
        }
    ]
 
    // ...
}
                                            

You change a camera's flash mode using CameraSettings. First, you need to set up a CameraSettings object.

// In your app's header file
// declare a pointer to a CameraSettings object
bb::cascades::multimedia::CameraSettings* m_pCameraSettings;
 
// In your app's .cpp file
// instantiate the pointer
m_pCameraSettings = new CameraSettings();
 
// Set the pointer to point to our camera's settings
cameraObj->getSettings(m_pCameraSettings);
 
// In your app's destructor, delete this pointer
// to avoid a memory leak
m_pCameraSettings->deleteLater();                    
                    

You can use QML to set up your UI and the Actions bar that's used to select and apply a new flash mode setting. This approach is similar to the QML sample code; however, there are some key differences. For example, the onTriggered() signal handler calls the app.changeFlashMode() function. This function is marked Q_INVOKABLE in the app's header file, which connects it to the C++ code where the function is implemented. Another difference to note is that the objectName property is defined for the Camera control. This objectName property makes the camera control and its properties accessible to your app's C++ code.

import bb.cascades 1.0
import bb.cascades.multimedia 1.0
 
Page {
    titleBar: TitleBar {
        title: "C++ Camera Sample App"
    }
    Container {
        attachedObjects: [
        ]
        Container {
            // The Camera object
            Camera {
                objectName: "qmlCameraObj"
            }
        }
    }

    // Actions menu
    actions: [
        ActionItem {
            title: "Flash Mode: Off"
            ActionBar.placement: ActionBarPlacement.InOverflow
            onTriggered: {
                app.changeFlashMode(0)
            }
        },
        ActionItem {
            title: "Flash Mode: On"
            ActionBar.placement: ActionBarPlacement.InOverflow
            onTriggered: {
                app.changeFlashMode(1)
            }
        },
        ActionItem {
            title: "Flash Mode: Auto"
            ActionBar.placement: ActionBarPlacement.InOverflow
            onTriggered: {
                app.changeFlashMode(2)
            }
        },
        ActionItem {
            title: "Flash Mode: Light"
            ActionBar.placement: ActionBarPlacement.InOverflow
            onTriggered: {
                app.changeFlashMode(3)
            }
        }
    ]

    // ...    
}
// In your app's header file
class ApplicationUI : public QObject
{
    QOBJECT
    public:
        ApplicationUI(Application *app);
        virtual ~ApplicationUI();

        Q_INVOKABLE
        void changeFlashMode(int);

    // ...
                        
}

Next, you implement the function that changes the flash mode. This function takes one integer parameter that represents the new flash mode to set. You must use an integer because you can't pass an enum from your QML code to your C++ code.

void ApplicationUI::changeFlashMode(int newFlashMode)
{
   m_pCamera->getSettings(m_pCameraSettings);

   // You must cast newFlashMode to a CameraFlashMode::Type
   // to pass it to the setFlashMode function
   m_pCameraSettings->setFlashMode(CameraFlashMode::Type(newFlashMode));
   m_pCamera->applySettings(m_pCameraSettings);
}
                   

Flash modes are defined in camera_flashmode_t. The following code sample demonstrates how to turn on flash mode.

#include <camera/camera_api.h>

camera_error_t err;

/* Find out if flash modes are supported */
if (camera_can_feature(camera_handle, CAMERA_FEATURE_FLASH)) {
    /* Turn on flash mode */
	err = camera_config_flash(camera_handle, CAMERA_FLASH_ON);
	if (err == CAMERA_EOK) {
	    /* Flash mode set */
	} else {
	    /* Handle error */
	}
}

You can set many other properties using other API functions. For example, use camera_set_vf_property() to set viewfinder properties and camera_set_photo_property() to set photo properties. These properties are defined in camera_imgprop_t. You can set multiple properties with one call. Some of these properties must be set before starting the viewfinder (such as CAMERA_IMGPROP_WIN_GROUPID and CAMERA_IMGPROP_WIN_ID); others can be set while the viewfinder is running (for example, CAMERA_IMGPROP_FRAMERATE and CAMERA_IMGPROP_ZOOMFACTOR).

camera_error_t err;

err = camera_set_vf_property( camera_handle,
                         CAMERA_IMGPROP_WIN_GROUPID, "mygroup",
                         CAMERA_IMGPROP_WIN_ID, "vfwindow");			
if (err != CAMERA_EOK) {
    /* Handle error */
}	 
 
err = camera_set_photo_property( camera_handle,
                            CAMERA_IMGPROP_WIDTH, 2322,
                            CAMERA_IMGPROP_HEIGHT, 4128,
                            CAMERA_IMGPROP_ROTATION, 270 );
if (err != CAMERA_EOK) {
    /* Handle error */
}       

Trigger photo capture

When the user touches the screen, interested apps are notified. You can use the screen touch as the trigger to capture a photo. If your app is written in QML and C++, you can implement the photo capture in the signal handler of the touch() signal. If your app is written in C, it can register to receive screen events through BlackBerry Platform Services (BPS) and capture a photo when the screen touch event is received. For more information on screen events, see Handle screen events.

Call the capturePhoto() function in the onTouch() signal handler to take a photo. You can also define a photo capture flag to monitor the photo capture process. In the following code sample, a photo capture flag called photoBeingTaken is defined as a property, and used in the onTouch(), onViewfinderStarted(), onImageCaptureFailed(), and onPhotoSaved() signal handlers.

import bb.cascades.multimedia 1.0
import bb.multimedia 1.0
import bb.cascades 1.2
import bb.system 1.2
 
Page {
    // ...
 
    content: Container {
        // ...
 
        Camera {
            id: qmlCameraObj

            // The photo capture flag
            property bool photoBeingTaken;
              
             // ...
             
            onTouch: {
                if (photoBeingTaken == false) {
                    photoBeingTaken = true;
                    qmlCameraObj.capturePhoto();
                }
            }
             
            onViewfinderStarted: {
                photoBeingTaken = false;
            }
             
            onImageCaptureFailed: {
                photoBeingTaken = false;
            }
             
            onPhotoSaved: {
                photoBeingTaken = false;
            }
             
           // ...
 
        }
    }
}                       
                    

Your app can implement an onTouch() slot and connect the slot to the touch() signal. In onTouch(), call capturePhoto() to take a photo.

// In the ApplicationUI constructor,
// connect onTouch() with the touch() signal 

bool result;
// ... 

result = connect(m_pCamera,
                 SIGNAL(touch(bb::cascades::TouchEvent*)),
                 this,
                 SLOT(onTouch()));

Q_ASSERT(result);


// Take a photo when receiving the touch() signal 
void ApplicationUI::onTouch()
{
    if (m_PhotoBeingTaken == false)
    {
        m_PhotoBeingTaken = true;
        m_pCamera->capturePhoto();
    }
}                        
                    

Check for the SCREEN_EVENT_MTOUCH_TOUCH event. This event indicates that the user has touched the screen. Take a photo by calling camera_take_photo().

/* When receiving SCREEN_EVENT_MTOUCH_TOUCH,
   take a photo
 */
/* ... */

if (touch) {
    touch = false;
    err = camera_take_photo(handle,
                            &shutter_callback,
                            NULL,
                            NULL,
                            &image_callback,
                            NULL,
                            false);   
    if (err == CAMERA_EOK) {
        /* Photo capture successful */
    } else {
        fprintf(stderr, "camera_take_photo() error %d", err);
    }
}
                   

Play a shutter sound

The Camera libraries don't automatically play audible shutter sounds when a picture is taken or a video is recorded. Camera apps must supply their own sound when a photo is captured or a video recording begins and ends. Although you can choose to not have a shutter sound when taking a picture or a video, you are responsible for ensuring that your app adheres to the local laws of the regions in which you distribute the app. For example, it is illegal to mute or change the shutter sound of a camera app in Japan or South Korea. For more information, see the BlackBerry World Vetting Criteria.

When you take a photo, the shutterFired() signal is emitted. In the QML camera control definition, include a SystemSound object as an attached object. In the signal handler, play the shutter sound.

Container {
    // The QML Camera object
    Camera {    
        id: qmlCameraObj
        property bool photoBeingTaken  

        attachedObjects: [
            SystemSound {
              id: shutterSound
              sound: SystemSound.CameraShutterEvent
            },
            // ...
        ]  

        // Play the shutter sound
        onShutterFired: {
            shutterSound.play();
        }

        // ...

    }
    // ...
}                                

When you take a photo, the shutterFired() signal is emitted.

Call SystemSound::play() in the onShutterFired() slot that is connected to the shutterFired() signal.

void ApplicationUI::onShutterFired(){   
      SystemSound::play(SystemSound::CameraShutterEvent);
}                        
                    

You play the shutter sound in the shutter_callback() you pass in to the camera_take_photo() function.

#include <bps/soundplayer.h>
#include <camera/camera_api.h>
/* ... */

static void
shutter_callback(camera_handle_t handle,
                 void* arg) 
{
    soundplayer_play_sound("event_camera_shutter");
}          

Handle preview images

If you are using the Camera C++ API, you can follow the steps below to preview viewfinder frames when they become available.

  1. Add at least one preview buffer to the viewfinder buffer pool.
  2. Listen for the previewFrameAvailable() signal, which contains a pointer to the image data.
  3. Define the onPreviewFrameAvailable() signal handler to receive and process the signal.

You can create a PreviewFrameProcessor class to separate your image-processing code from your other camera app code. This approach allows you to use a multithreaded approach to image processing, which avoids blocking your main UI thread and keeps your UI responsive during image-processing tasks.

If you are using the Camera C API, you can implement the callbacks you need and pass them to the camera_take_photo() function. For example, implement the postview_callback() and the image_callback().

Not applicable

In the main app class, declare private variables for the preview frame processor and the camera objects.

class ApplicationUI : public QObject
{
    // ...
                
    private:
        bool m_PhotoBeingTaken;
        
        // Define a pointer variable for your preview 
        // frame processing class
        PreviewFrameProcessor* m_pProcessor;
        
        // Define pointers to your camera and the
        // camera settings objects
        Camera* m_pCamera;
        CameraSettings* m_pCameraSettings;

        // ...
};
                   

In the app constructor, initialize the preview frame processor and connect the previewFrameAvailable() signal to the onPreviewFrameAvailable() slot.

ApplicationUI::ApplicationUI(Application *app) : QObject(app)
{
    // ...

    m_pProcessor = new PreviewFrameProcessor();

    // Connect signals and slots

    // ...
    
    result = connect(m_pCamera,
                     SIGNAL(previewFrameAvailable(
                       bb::cascades::multimedia::SharedUCharPointer, 
                       quint64, 
                       unsigned int, 
                       unsigned int, 
                       unsigned int)),
                     m_pProcessor,
                     SLOT(onPreviewFrameAvailable(
                       bb::cascades::multimedia::SharedUCharPointer, 
                       quint64, 
                       unsigned int, 
                       unsigned int, 
                       unsigned int)));

    Q_ASSERT(result);

    // ...

    // Set the settings pointer to the camera's settings
    m_pCamera->getSettings(m_pCameraSettings);

    // Set the camera pointer in your PreviewFrameProcess object
    // to point to your camera object
    m_pProcessor->setCamera(m_pCamera);
                    
    // ...
}

The PreviewFrameProcessor class includes a setCamera() function that takes a pointer to a Camera object. This function connects your Camera object to the PreviewFrameProcessor object.

When the previewFrameAvailable() signal is emitted, the PreviewFrameProcessor object's onPreviewFrameAvailable() signal handler is called to handle it. This signal handler performs all image processing, and is also where your app replaces the preview buffer that's consumed during image processing.

void PreviewFrameProcessor::setCamera(Camera* pCamObj)
{
    pCameraObj = pCamObj;
}

void PreviewFrameProcessor::onPreviewFrameAvailable(
        bb::cascades::multimedia::SharedUCharPointer previewBuffer,
        quint64 size,
        unsigned int width,
        unsigned int height,
        unsigned int stride)
{
    // Stop 'unused parameter' compiler errors
    Q_UNUSED(width);
    Q_UNUSED(height);
    Q_UNUSED(stride);

    // *********************************************
    //     Perform your image processing here
    //     ...
    // *********************************************

    // The original buffer is consumed by this operation,
    // so you must add a new buffer to the viewfinder buffer
    // pool to replace the one that was consumed
    pCameraObj->addPreviewBuffer(previewBuffer, size);
}
                    

The following code sample demonstrates how to use the image_callback() to save the final image to a file. The callback checks the frame type of the available image. If the image is in JPEG format, the callback creates a file in the camera roll directory and saves the image to the new file.

#include <camera/camera_api.h>
#include <fcntl.h>

static void
image_callback(camera_handle_t handle,
               camera_buffer_t* buf,
               void* arg)
{
    if (buf->frametype == CAMERA_FRAMETYPE_JPEG) {
        fprintf(stderr, "still image size: %lld\n", buf->framedesc.jpeg.bufsize);
        int fd;
        char filename[CAMERA_ROLL_NAMELEN];

        /* Create and open a file for writing */
        if (camera_roll_open_photo(handle,
                                   &fd,
                                   filename,
                                   sizeof(filename),
                                   CAMERA_ROLL_PHOTO_FMT_JPG) == CAMERA_EOK) {
            fprintf(stderr, "saving: %s\n", filename);

            /* Write the image to file */
            int index = 0;
            while(index < (int)buf->framedesc.jpeg.bufsize) {
                int rc = write(fd, &buf->framebuf[index], 
                               buf->framedesc.jpeg.bufsize-index);
                if (rc > 0) {
                    index += rc;
                } else if (rc == -1) {
                    if ((errno == EAGAIN) || (errno == EINTR)) {
                        continue;
                    }
                    perror("write");
                    break;
                }
            }
            close(fd);
        } else {
            /* Handle error */
        }
    }
}
                   

Last modified: 2015-05-07



Got questions about leaving a comment? Get answers from our Disqus FAQ.

comments powered by Disqus