Purpose

Exif is a file format specification for digital still images and associated sound. Exif API handles the JPEG based Exif image file format. It is an independent library providing services for reading, writing and modifying Exif v2.2 compliant data. It offers an interface for general operations related to basic Exif data as well as for advanced operations, and thus it may be used with subsets of Exif, such as DCF. Users of this library include e.g. the following:

  • Image viewer applications, which read and modify Exif data.

  • Interfaces/libraries providing Exif compliant JPEG images.

Constraints

This API is valid for all platforms running on Symbian OS v9.3 or later.

Classification and release information

The Exif API is an SDK API and was first published in S60 3rd Edition.

API Description

The Exif API does not have any relationships to the Symbian platform subsystems. It only requires the basic Symbian platform. The Exif API supports reading, writing and modifying Exif data. Particularly, it supports operations related to tags, IFDs and thumbnails. IFDs store tags so that they are collected into groups under the same category. Thumbnail image data is not presented as an IFD or tag, but it is independent data tied to the first IFD which describes its properties. A tag is the smallest unit of the data structure stored and moved through the interface. The library interface provides both basic and advanced services. The basic interface services provide abstracted interface functions to read, write and modify the most common Exif data including mainly the mandatory and recommended tags. The advanced interface services provide more flexible lower-level operations to read, write and modify Exif data. The Exif API is not intended to be used as such. It offers services that are needed by other libraries supporting Exif. Those libraries can use Exif API in order to provide the requested service.

Use Cases

The main use cases of Exif API are:

Use Cases


Use Cases

API Class Structure

There are four interface classes, CExifRead , CExifModify , CExifTag and TExifTagInfo which provides the lowest level interface for an individual tag. TOperationMode of the CExifModify class is used to define the operation mode of the class. The mode can be either ECreate to create an Exif image from the given JPEG image data, or EModify to modify an existing Exif image. CExifReadImpl , CExifModifyImpl and CExifTagImpl are the implementation classes of the interfaces.

Exif API class diagram


Exif API class diagram

Related APIs
  • CExifModify
  • CExifModifyImpl
  • CExifRead
  • CExifReadImpl
  • CExifTag
  • CExifTagImpl
  • ECreate
  • EModify
  • TExifTagInfo
  • TOperationMode

Using Exif API

Parsing an existing Exif image

In this example the full validity checking is done:

             
              // 1. Read Exif image from the file to a buffer...
              
RFile file;
User::LeaveIfError( file.Open( iFs, iExifFile->Des(), EFileRead ) );
CleanupClosePushL( file );
TInt size = 0;
file.Size(size);
HBufC8* exif = HBufC8::NewL( size );
CleanupStack::PushL( exif );
TPtr8 bufferDes( exif->Des() ); 
User::LeaveIfError( file.Read( bufferDes ) );
CleanupStack::Pop( exif );
CleanupStack::PopAndDestroy();
CleanupStack::PushL( exif );

// 2. Instantiate Exif reader...
CExifRead* read = CExifRead::NewL( exif->Des() );
CleanupStack::PushL( read );

// 3. Get required data from the Exif image...
HBufC8* data = NULL;
data = read->GetImageDescriptionL(); /* Leaves if data is not found. */
/* Process the data … */
delete data;
data = NULL;

// 4. Delete the reader instance...
CleanupStack::PopAndDestroy( read );
CleanupStack::PopAndDestroy( exif );

Parsing an existing Exif image with options

In this example the validity checking for the Exif tags or JPEG markers is not done. The execution time is much shorter with bigger images.

             
              // 1. Read Exif information from the file to a buffer...
              
RFile file;
User::LeaveIfError( file.Open( iFs, iExifFile->Des(), EFileRead ) );
CleanupClosePushL( file );
TInt size = 0;
file.Size(size);
// Don’t read more than 64k
if ( size > 65536 )
    size = 65536;
HBufC8* exif = HBufC8::NewL( size );
CleanupStack::PushL( exif );
TPtr8 bufferDes( exif->Des() );
User::LeaveIfError( file.Read( bufferDes, size ) );
CleanupStack::Pop( exif );
CleanupStack::PopAndDestroy();
CleanupStack::PushL( exif );

// 2. Instantiate Exif reader in fast mode...
CExifRead* read = CExifRead::NewL( exif->Des(),
                               CExifRead::ENoTagChecking | CExifRead::ENoJpeg );
CleanupStack::PushL( read );

// 3. Get required data from the Exif image...
HBufC8* data = NULL;
data = read->GetImageDescriptionL(); /* Leaves if data is not found. */
/* Process the data … */
delete data;
data = NULL;

// 4. Delete the reader instance...
CleanupStack::PopAndDestroy( read );
CleanupStack::PopAndDestroy( exif );

Modifying an existing Exif image

             
              // 1. Read Exif image from the file to a buffer...
              
RFile file;
User::LeaveIfError( file.Open( iFs, iExifFile->Des(), EFileRead ) );
CleanupClosePushL( file );
TInt size = 0;
file.Size(size);
HBufC8* exif = HBufC8::NewL( size );
CleanupStack::PushL( exif );
TPtr8 bufferDes( exif->Des() );
User::LeaveIfError( file.Read( bufferDes ) );
CleanupStack::Pop( exif );
CleanupStack::PopAndDestroy();
CleanupStack::PushL( exif );

// 2. Instantiate Exif modifier in EModify mode...
CExifModify* modify = CExifModify::NewL( exif->Des(), CExifModify::EModify );
CleanupStack::PushL( modify );

// 3. Modify required data in the Exif image...
modify->SetXResolutionL( 72, 1 ); 

// 4. Get the modified Exif image...
// If zero length descriptor is given instead of exif->Des(), then only the
// Exif meta data is returned.
HBufC8* modifiedExif = modify->WriteDataL( exif->Des() );
/* Process the modified Exif data */
delete modifiedExif;
modifiedExif = NULL;

// 5. Delete the modifier instance...
CleanupStack::PopAndDestroy( modify );
CleanupStack::PopAndDestroy( exif );

Creating an Exif image out of an existing JPEG image

             
              // 1. Read JPEG image from the file to a buffer...
              
RFile file;
User::LeaveIfError( file.Open( iFs, iExifFile->Des(), EFileRead ) );
CleanupClosePushL( file );
TInt size = 0;
file.Size(size);
HBufC8* jpeg = HBufC8::NewL( size );
CleanupStack::PushL( jpeg );
TPtr8 bufferDes( jpeg->Des() );
User::LeaveIfError( file.Read( bufferDes ) );
CleanupStack::Pop( jpeg );
CleanupStack::PopAndDestroy();
CleanupStack::PushL( jpeg );

// 2. Instantiate Exif modifier in ECreate mode...
CExifModify* modify = CExifModify::NewL( jpeg->Des(), CExifModify::ECreate );
CleanupStack::PushL( modify );

// 3. Insert (Set) at least the mandatory data...
modify->SetXResolutionL( 72, 1 ); 
modify->SetYResolutionL( 72, 1 ); 
modify->SetResolutionUnitL( 2 );
modify->SetYCbCrPositioningL( 1 );
modify->SetComponentsConfigurationL( 1, 2, 3, 0 );
modify->SetColorSpaceL( 1 );
modify->SetPixelXDimensionL( KImageWidth );
modify->SetPixelYDimensionL( KImageHeight );

// 4. Get the new Exif image...
// If zero length descriptor is given instead of jpeg->Des(), then only the
// Exif meta data is returned.
HBufC8* newExif = modify->WriteDataL( jpeg->Des() );
/* Process the new Exif data */
delete newExif;
newExif = NULL;

// 5. Delete the modifier instance...
CleanupStack::PopAndDestroy( modify );
CleanupStack::PopAndDestroy( jpeg );

Creating Exif data without a JPEG image

             
              // 1. Instantiate Exif modifier in ECreate mode...
              
CExifModify* modify = CExifModify::NewL();
CleanupStack::PushL( modify );

// 3. Insert (Set) at least the mandatory data...
modify->SetXResolutionL( 72, 1 ); 
modify->SetYResolutionL( 72, 1 ); 
modify->SetResolutionUnitL( 2 );
modify->SetYCbCrPositioningL( 1 );
modify->SetComponentsConfigurationL( 1, 2, 3, 0 );
modify->SetColorSpaceL( 1 );
modify->SetPixelXDimensionL( KImageWidth );
modify->SetPixelYDimensionL( KImageHeight );

// 4. Get the new Exif meta data...
// If a descriptor containing valid JPEG data is given instead of zero length 
// descriptor, then the whole Exif image data is returned.
TPtrC8 zeroLengthDesc;
HBufC8* newExif = modify->WriteDataL( zeroLengthDesc );
/* Process the new Exif data */
delete newExif;
newExif = NULL;

// 5. Delete the modifier instance...
CleanupStack::PopAndDestroy( modify );

Error handling

The leave mechanism of the Symbian platform is used to handle memory exhaustion. The Exif API leaves whenever it detects something from which it cannot recover. The exception/error cases are listed below:

Out of memory.

KErrGeneral

An internal error occurred.

KErrArgument

The given parameter to the API function is incorrect or invalid.

KErrNotSupported

This library does not support the requested operation with the given parameters.

KErrCorrupt

The given JPEG or Exif data is corrupted or invalid.

KErrNotFound

The data (tag or IFD) corresponding to the given parameter is not found in the JPEG or Exif data.

KErrNotReady

The Exif data is not yet complete (valid) for writing. Mandatory tags or thumbnail may be missing.

KErrOverflow

The APP1 marker segment size exceeds 64K if the given data is inserted to the Exif data.

The users of the Exif API should be aware of the following considerations:

  • While instantiating an Exif reader or modifier (in the EModify mode), the whole Exif data (containing the Exif application marker and the JPEG compressed image data) must be provided. The Exif application marker is checked for the Exif v2.2 and/or DCF v1.0 format validity, which also covers the prior but no further versions. The JPEG compressed primary image data is also simply checked for JPEG baseline validity, but it is still the user’s responsibility to provide valid and correct image data.

  • With TExifModifyOption in modifier or TExifReadOption in reader the user may enable faster parsing times when primary JPEG data markers are not verified. With the ENoJpeg option in reader only 64 kB of data is needed to read to the buffer, so this provides significant time saving with large images. With the ENoTagChecking option the reader can open Exif images that are not fully compatible with Exif specifications.

  • While instantiating an Exif modifier (in the ECreate mode), the whole JPEG data must be provided. The given data is simply checked for JPEG baseline format validity. JPEG images containing an SOF marker other than SOF0 (baseline) are not supported. The image may contain any application or comment markers. These markers are discarded while writing the Exif data. It is the user’s responsibility to provide valid and correct image data.

  • It is also possible to instantiate an Exif modifier (in the ECreate mode) without providing any input data. In this case, no checking can be performed for the image data. It is the user’s responsibility to use the Exif data with a proper image data.

  • The Exif API supports reading both Little Endian and Big Endian Exif data, but written Exif output is always in the Little Endian format. In the modifying case, even if the input Exif data is in the Big Endian format, the output Exif data is in the Little Endian format.

  • While inserting a thumbnail into Exif data, the given thumbnail image data must be JPEG compressed. The thumbnail image is simply checked for JPEG baseline validity, but it is still the user’s responsibility to provide valid and correct image data.

  • While writing Exif data output ( CExifModify::WriteDataL ), the original JPEG or Exif image must be provided again. Although a simple crosscheck is done before writing the Exif output, it is the user’s responsibility to provide the original (or identical) JPEG or Exif image. If a zero-length buffer is provided instead of the original image data, then only the Exif Meta data is returned (written).

  • While getting the Exif APP segment data ( CExifRead::GetExifAppSegment ), only the whole APP1 segment containing the Exif specific data is returned. The segment does not include the primary JPEG image, but includes the Exif thumbnail image if one exists.

Related APIs
  • CExifModify::WriteDataL
  • CExifRead::GetExifAppSegment
  • ECreate
  • EModify
  • ENoJpeg
  • ENoTagChecking
  • KErrArgument
  • KErrCorrupt
  • KErrGeneral
  • KErrNotFound
  • KErrNotReady
  • KErrNotSupported
  • KErrOverflow
  • TExifModifyOption
  • TExifReadOption

Memory overhead

Since the maximum size of an Exif marker is 64 kB (limited by the JPEG application marker segment), memory consumption is not essentially higher than 64 kB in most operations. However, there are two operations where memory consumption may be higher:

  • While getting out the whole Exif image using the CExifModify::WriteDataL function, the instant memory consumption may reach up to twice the JPEG image data size.

  • While getting out the Exif APP1 segment using the CExifRead::GetExifAppSegmentL function, the instant memory consumption may reach up to twice the Exif APP1 segment data size.

Related APIs
  • CExifModify::WriteDataL
  • CExifRead::GetExifAppSegmentL

Glossary

Abbreviations

Abbreviations

DCF

Design rule for the Camera File system

Exif

Exchangeable image file format for digital still cameras

OOM

Out Of Memory

Definitions

Definitions

IFD Image File Directory. A collection of related tags. For example, the first IFD includes all the tags related to an Exif file’s thumbnail.

JPEG

Still image compression standard developed by the Joint Photographer Experts Group.

Primary image

The actual JPEG image data of the Exif file.

Tag

The smallest unit of data handled by this library. It is stored inside an IFD.

References

Exchangeable image file format for digital still cameras: Exif version 2.2. http://www.exif.org/

Design Rule for Camera File System 1.0

http://www.exif.org/