Platform Integration: Extern Bitmap interface

At the runtime of the application, the content of existing bitmap resources can't be exchanged nor new resources can be added. This prevents the bitmap resources from being suitable to provide image contents determined dynamically at the runtime e.g. loaded from an SD memory card, received from a network adapter or rendered by a third-party application, like the map view in a GPS navigation system.

In order to be able to deal with such demanding application cases, the Mosaic framework provides the class Resources::ExternBitmap. Unlike bitmap resources, objects of this class are optimized to represent and manage image contents being obtained or rendered dynamically at the runtime of the GUI application - thus unknown at the compilation time.

This functionality depends on an interface you have to implement in your particular target system. Doing this you can precisely control how the dynamic image contents are found, loaded, decoded and eventually color converted. It's up to you whether the contents are loaded from an SD memory card, received from a network adapter or rendered dynamically by third-party application.

If you intend to display dynamically loaded image contents, this chapter will provide you with information how you implement the interface between the GUI application and your particular image provider. In turn, how the Extern Bitmap objects are used within the GUI application is described in the chapter Displaying dynamically loaded images.

Function EwLoadExternBitmap()

The interface to integrate the GUI application with your particular, platform specific image provider consists of a single ANSI C function named EwLoadExternBitmap(). You will need to implement this function and ensure, that it is compiled and linked with your entire application. The function is declared as follows:

XBitmap* EwLoadExternBitmap( XString aName )

The function expects a single parameter aName. The value passed in this parameter does always correspond to the value specified in the property Name of the Extern Bitmap object causing the invocation of the function. The property Name and thus the parameter aName are used to identify the image content, the function EwLoadExternBitmap() should deliver.

Depending on your application case, aName could be understood as path to an image file existing on an SD memory card or as an URL to a network location from which the image should be received. It's up to you how you use the property Name and the parameter aName. Since both are declared as string (XString) you are flexible to pass any information you need to identify the desired image content.

For example, an application intended to show images from an SD memory card can use the parameter aName to address the corresponding file on the file system and to specify an optional flag indicating whether you want the image in its original size or as small thumbnail. Passing the value "/IMAGE123.JPG" in this parameter could be understood by your implementation of the EwLoadExternBitmap() function as provide the content of the image file IMAGE123. In turn the value "/IMAGE123.JPG (THUMB)" could be understood by the interface as provide the thumbnail content of the image file IMAGE123. Here the additional suffix (THUMB) could instruction your implementation to decode the file as a thumbnail.

Once the parameter aName is evaluated, your implementation of the function EwLoadExternBitmap() should create a new bitmap, fill it with the particular image content and return the bitmap. That's all. In case of an error, e.g. when the requested image content is not available, the function should return NULL. Similarly, if the parameter aName is an empty string, the function should also return NULL.

The following are the typical steps you have to take care of when implementing the function EwLoadExternBitmap():

Step 1: Evaluate the parameter aName. If this parameter is composed of several operands (like the example above with the optional (THUMB) suffix), extract and process the operands.

Step 2: Knowing the name of the desired image content determine its size in pixel (width and height). If the image content is not available (for example, the parameter aName addresses a non existing file), abort the operation and return NULL.

Step 3: Create a new Embedded Wizard bitmap to accommodate the image content. The size of the bitmap should correspond to the size of the image determined in the preceding step. If the bitmap creation fails due to out-of-memory, abort the operation and return NULL.

Step 4: Lock the entire bitmap for write operation. With this operation you will obtain a data structure with pointers to the memory where the bitmap pixel are stored. Having this information you can access and fill the bitmap with the image content.

Step 5: Copy pixel-by-pixel the content of the image into the memory of the previously locked bitmap. If necessary you can apply during this step an additional color conversion or color reduction. For example, if the image content is stored originally with 32-bit per pixel RGBA8888 format but your target is running in RGBA4444 color format, you will need to convert the color values from RGBA8888 to RGBA4444.

IMPORTANT

Please note, Embedded Wizard supports bitmaps with various color formats. Which color format is used in your particular case does depend on the version of your Platform Package. You should consider, that the color format affects the layout of how the pixel are stored and coded in the bitmap memory. For details explaining the different color formats see the chapter XBitmapLock.

Step 6: Once you are finished with the copy operation, unlock the bitmap again.

Step 7: Eventually release all resources used to find, load and decode the image.

Step 8: Return the bitmap.

The following example demonstrates the typical implementation of the EwLoadExternBitmap() function. For the sake of simplicity, this example doesn't load any real image file. Instead it fills the bitmap with a solid color. The size of the bitmap and the color to fill it are determined by evaluating the parameter aName. If aName is "BLUE 100x50", the implementation creates a 100x50 pixel large bitmap and fills it with blue color. If the parameter is "SEMI-RED 200x100", a semi-transparent red bitmap with the corresponding size is created. All other aName values are considered as invalid and result in the function returning NULL. Furthermore, in this example we assume you target system (your Platform Package) is running in the color format RGBA8888:

/* Include necessary header files */
#include "ewrte.h"
#include "ewgfxdriver.h"
#include "ewextgfx.h"
#include "ewgfxdefs.h"
#include "ewextpxl_RGBA8888.h"
#include <string.h>


XBitmap* EwLoadExternBitmap( XString aName )
{
  char          name[32];
  int           width;
  int           height;
  unsigned int  clr_red, clr_green, clr_blue, clr_alpha;
  XBitmap*      bitmap;
  XPoint        frameSize;
  XRect         lockArea;
  XBitmapLock*  lock;
  unsigned int* dest;
  int           ofs;
  int           x, y;

  /* STEP 1 */
  
  /* Convert the 16-bit wide character string in 8-bit ANSI string */
  EwStringToAnsi( aName, name, sizeof( name ), 0 );

  /* STEP 1 and 2 */

  /* The blue bitmap is requested? aName == "BLUE 100x50". Determine
     the size and the color to fill the bitmap. */
  if ( !strcmp( name, "BLUE 100x50" ))
  {
    width      = 100;
    height     = 50;
    clr_red    = 0;
    clr_green  = 0;
    clr_blue   = 255;
    clr_alpha  = 255;
  }
  
  /* The red bitmap is requested? aName == "RED 200x100". Determine
     the size and the color to fill the bitmap. */
  else if !strcmp( name, "SEMI-RED 200x100" ))
  {
    width      = 200;
    height     = 100;
    clr_red    = 255;
    clr_green  = 0;
    clr_blue   = 0;
    clr_alpha  = 128;
  }

  /* The requested image is not available */  
  else
    return NULL;

  /* STEP 3 */

  /* Create a new bitmap with the previously determined size */
  frameSize.X = width;
  frameSize.Y = height;
  bitmap      = EwCreateBitmap( EW_PIXEL_FORMAT_NATIVE, frameSize, 0, 1 );
  
  /* Enough memory to create the bitmap? */
  if ( bitmap == NULL )
    return NULL;
  
  /* STEP 4 */
  
  /* Lock the entire bitmap for write operation */
  lockArea.Point1.X = 0;
  lockArea.Point1.Y = 0;
  lockArea.Point2.X = width;
  lockArea.Point2.Y = height;
  lock              = EwLockBitmap( bitmap, 0, lockArea, 0, 1 );
  
  /* STEP 5 */
  
  /* Get the pointer to the first pixel within the locked bitmap. In the
     RGBA8888 format every pixel is a 32-bit value (unsigned int). 
     Additionally calculate the offset in pixel between the end of one row
     and the begin of the next row. */
  dest   = (unsigned int*)lock->Pixel1;
  ofs    = ( lock->Pitch1Y / 4 ) - width;

  /* Iterate through the pixel within the locked bitmap area. Do this
     row-by-row and column-by-column. After one row is finished adjust the
     'dest' pointer to refer to the next row. After one column is finished
     increment the 'dest' pointer only. */
  for ( y = 0; y < height; y++, dest += ofs )
    for ( x = 0; x < width; x++, dest++ )
    {
      /* The color value you want to store in the pixel. Every variable
         is valid in range 0 .. 255. */
      unsigned int red   = clr_red;
      unsigned int green = clr_green;
      unsigned int blue  = clr_blue;
      unsigned int alpha = clr_alpha;

      /* In the color format RGBA8888, the color components 'red', 'green'
         and 'blue' can be premultiplied by 'alpha' component. Should this
         occur in your Platform Package?

         Please note, to optimize the implementation we divide the result
         of the multiplication by 256 (shift right 8) instead of by 255.
         Thus to reduce the calculation errors we increase the alpha value. */
      #ifdef EW_PREMULTIPLY_COLOR_CHANNELS
        red   = (( red   * ( alpha + 1 )) >> 8 );
        green = (( green * ( alpha + 1 )) >> 8 );
        blue  = (( blue  * ( alpha + 1 )) >> 8 );
      #endif

      /* In the color format RGBA8888, the arrangement of the color components
         'red', 'green', 'blue' and 'alpha' can be configured. Ensure, that all
         components are stored at right bit offsets within the 32-bit value of
         the pixel */
      red   <<= EW_COLOR_CHANNEL_BIT_OFFSET_RED;
      green <<= EW_COLOR_CHANNEL_BIT_OFFSET_GREEN;
      blue  <<= EW_COLOR_CHANNEL_BIT_OFFSET_BLUE;
      alpha <<= EW_COLOR_CHANNEL_BIT_OFFSET_ALPHA;
     
      /* Now compose the color components to a single 32-bit value and store
         the result in the bitmap memory ... */
      *dest = red | green | blue | alpha;
    }

  /* STEP 6 */

  /* Don't forget to unlock the bitmap when you are done! */
  EwUnlockBitmap( lock );
  
  /* STEP 8 */
  
  /* Return the bitmap */
  return bitmap;
}

Take in account the color format of the bitmap

In the code example from the section above we have simply assumed, that the bitmaps do store the pixel as 32-bit RGBA8888 values. This, however, is not always the case. When you intend to access and modify pixel data of a bitmap created with the format EW_PIXEL_FORMAT_NATIVE you should always consider, that the real color format of the bitmap does depend on the version of the Platform Package used in your target system.

Our Platform Packages are optimized to work with the color format supported natively by the graphics hardware of the particular target system (this is usually the color format of the frame-buffer). Accordingly, the version of the Platform Package implies the format in which all EW_PIXEL_FORMAT_NATIVE bitmaps are stored. In the table below you will find detailed documentation describing and demonstrating how you access and modify the pixel data depending on the version of your Platform Package:

Your Platform Package version

The format of how EW_PIXEL_FORMAT_NATIVE bitmaps are stored

RGBA8888, RGB888 and RGB565

RGBA8888

RGBA4444

RGBA4444

LumA44

LumA44

Index8

Index8

Besides the above described target specific EW_PIXEL_FORMAT_NATIVE color format, every Platform Package supports following two universal and one optional formats. If your application case it requires, you can adapt the implementation of the EwLoadExternBitmap() function to create and load bitmaps of those formats:

Format

Description

EW_PIXEL_FORMAT_ALPHA8

Universal 8-bit per pixel alpha only format. As such it doesn't provide any color information. It is thus required to explicitly specify the desired color at the runtime as a solid color value or a linear color gradient (e.g. in the Image view). ALPHA8 bitmaps are ideal for all application cases, where monochrome contents should change the colors dynamically at the runtime. Please see XBitmapLock for information about how the pixel data of such bitmap are modified.

EW_PIXEL_FORMAT_INDEX8

Universal 8-bit per pixel palette format. This format expects an additional color palette for translation between an 8-bit index and the native color value. The colors within the palette are determined by using the function EwModifyBitmapPalette(). Please see XBitmapLock for information about how the pixel data of such bitmap are modified.

EW_PIXEL_FORMAT_RGB565 (optional)

Universal 16-bit per pixel RGB format without any opacity information. Please see XBitmapLock for information about how the pixel data of such bitmap are modified.

For example, if you need to implement the EwLoadExternBitmap() function to create and load an EW_PIXEL_FORMAT_ALPHA8 bitmap, adapt the first parameter in the invocation of the EwCreateBitmap() function. Please note, when modifying the bitmap, ALPHA8 bitmaps are stored with 8-bit per pixel as described in the chapter XBitmapLock:

/* Include necessary header files */
#include "ewrte.h"
#include "ewgfxdriver.h"
#include "ewextgfx.h"
#include "ewgfxdefs.h"


XBitmap* EwLoadExternBitmap( XString aName )
{
  [...]

  /* ALPHA8 bitmaps are stored with 8-bit per pixel (unsigned char). 
     Accordingly adapt the declaration of the 'dest' variable. */
  unsigned char* dest;

  [...]

  /* STEP 3 */

  /* Create a new bitmap with the previously determined size */

  bitmap = EwCreateBitmap( EW_PIXEL_FORMAT_ALPHA8, frameSize, 0, 1 );
  
  [...]
  
  /* STEP 5 */
  
  /* Now get the pointer to the first pixel within the locked bitmap. In
     the ALPHA8 format every pixel is a 8-bit value (unsigned char).
     Additionally calculate the offset in pixel between the end of one row
     and the begin of the next row. */
  dest   = (unsigned char*)lock->Pixel1;
  ofs    = lock->Pitch1Y - width;

  /* Iterate through the pixel within the locked bitmap area. Do this
     row-by-row and column-by-column. After one row is finished adjust the
     'dest' pointer to refer to the next row. After one column is finished
     increment the 'dest' pointer only. */
  for ( y = 0; y < height; y++, dest += ofs )
    for ( x = 0; x < width; x++, dest++ )
    {
      /* The Opacity value you want to store in the pixel. The values lies
         in the range 0 .. 255. */
      unsigned char alpha = ...

      /* Store the alpha value in the bitmap memory ... */
      *dest = alpha;
    }

  [...]
}

Multi-frame and animated bitmaps

Similarly to the bitmap resource, every bitmap created dynamically by using the function EwCreateBitmap() can be configured as consisting of several individual images (so-called frames). Such bitmaps are called multi-frame bitmaps. When displaying a multi-frame bitmap, the number of the desired frame needs to be specified explicitly (e.g. in the Image view).

Multi-frame bitmaps are ideal wherever several versions of one and the same image are necessary (e.g. one for a pressed the other for a released button, etc.). If your application case it requires, you can implement the EwLoadExternBitmap() function to create and return a multi-frame bitmap. To achieve this, you simply specify the desired number of frames in the last parameter of the EwCreateBitmap() function. Please note, within a bitmap all frames will have equal size as determined by the second parameter (frameSize):

[...]

XBitmap* EwLoadExternBitmap( XString aName )
{
  [...]

  /* Create a new bitmap with 6 frames. Every frame will have the
     size 'frameSize'. */

  bitmap = EwCreateBitmap( EW_PIXEL_FORMAT_NATIVE, frameSize, 0, 6 );
  
  [...]
}

When creating multi-frame bitmaps your implementation of the EwLoadExternBitmap() should also be adapted to load every frame. In particular, you will need to lock, load and unlock every frame individually. Loading all frames at once is not possible since the frames are managed as individual memory areas:

[...]

XBitmap* EwLoadExternBitmap( XString aName )
{
  int frameNo;

  [...]

  /* STEP 3 */

  /* Create a multi-frame bitmap with 6 frames */
  frameSize.X = width;
  frameSize.Y = height;
  bitmap      = EwCreateBitmap( EW_PIXEL_FORMAT_NATIVE, frameSize, 0, 6 );
  
  /* The area to lock every bitmap frame */
  lockArea.Point1.X = 0;
  lockArea.Point1.Y = 0;
  lockArea.Point2.X = width;
  lockArea.Point2.Y = height;

  /* Every frame of the bitmap is treated individually */
  for ( frameNo = 0; frameNo < 6; frameNo++ )
  {
    /* Lock the given frame of the bitmap for write operation */
    lock = EwLockBitmap( bitmap, frameNo, lockArea, 0, 1 );
    
    [...]

    /* Use the pointers returned in the 'lock' data structure to load the
       bitmap frame with content (exact as as demonstrated in the examples
       in the sections above). */

    for ( y = 0; y < height; y++, dest += ofs )
      for ( x = 0; x < width; x++, dest++ )
      {
        [...]
      }

    /* Don't forget to unlock the bitmap frame */
    EwUnlockBitmap( lock );
  }

 [...]
}

Additionally, multi-frame bitmaps can be configured as containing animated video sequences. When displaying such bitmap in a view (e.g. Image view), the view will play back the bitmap frames autonomously. For this purpose you will need to specify the delay in milliseconds between two consecutive frames. You do this in the third parameter when creating the bitmap. Specifying a value less or equal 0 (zero) in this parameter will disable the animation for the affected bitmap:

[...]

XBitmap* EwLoadExternBitmap( XString aName )
{
  [...]

  /* Create a new animated bitmap with 16 frames and ~30 FPS animation speed */

  bitmap = EwCreateBitmap( EW_PIXEL_FORMAT_NATIVE, frameSize, 1000 / 30, 16 );
  
  [...]
}

Using PNG, JPG, BMP, GIF, etc. image decoders

Embedded Wizard provides only the interface permitting you to integrate the GUI application with your particular software or hardware image decoder or even with any other content provider (e.g. GPS application generating map views). A dedicated implementation of a PNG, JPG, BMP, etc. decoder is as such not available. It's up to you to take care of the necessary libraries to access the image contents, to load, decode or even render them dynamically (like the GPS application). Once you have your preferred library working on your target system, follow the instructions in the sections above to fill Embedded Wizard bitmaps with the provided image contents.

For inspiration purpose, the following code demonstrates the possible integration with libJPEG as decoder permitting EwLoadExternBitmap() to load and decode image files in the JPG format stored on the local file system. The implementation is optimized for the color format RGBA8888:

#include "ewrte.h"
#include "ewgfxdriver.h"
#include "ewextgfx.h"
#include "ewgfxdefs.h"
#include "ewextpxl_RGBA8888.h"
#include <stdio.h>
#include <string.h>
#include <ctype.h>
#include <stdlib.h>
#include "libjpeg/jpeglib.h"

/* This function has the job to create and fill a bitmap with content of an
   extern image file. aName identified extern file to load. If successful, an
   initialized bitmap is returned otherwise NULL. */
XBitmap* EwLoadExternBitmap( XString aName )
{
  struct jpeg_decompress_struct cinfo;
  struct jpeg_error_mgr         jerr;
  FILE*                         infile;
  JSAMPARRAY                    buffer;
  XBitmap*                      bitmap  = 0;
  XBitmapLock*                  lock    = 0;
  int                           nameLen = EwGetStringLength( aName );
  char*                         name    = malloc( nameLen + 1 );
  XPoint                        frameSize;
  XRect                         lockArea;

  /* Out of memory? */
  if ( !name )
    return NULL;

  /* Convert the 16-bit wide char string in an 8-bit ANSI string */
  EwStringToAnsi( aName, name, nameLen + 1, 0 );

  /* Try to open the file */
  if (( infile = fopen( name, "rb" )) == NULL )
  {
    free( name );
    return NULL;
  }

  /* Allocate and initialize JPEG decompression object. We set up the normal
     JPEG error routines. */
  cinfo.err = jpeg_std_error( &jerr );

  /* Now we can initialize the JPEG decompression object. */
  jpeg_create_decompress( &cinfo );

  /* Specify data source (eg, a file) */
  jpeg_stdio_src( &cinfo, infile );

  /* Read file parameters with jpeg_read_header() */
  jpeg_read_header( &cinfo, TRUE );

  /* Start decompressor */
  jpeg_start_decompress( &cinfo );

  /* Create an Embedded Wizard bitmap to store the image pixel data */
  frameSize.X = cinfo.output_width;
  frameSize.Y = cinfo.output_height;
  bitmap      = EwCreateBitmap( EW_PIXEL_FORMAT_NATIVE, frameSize, 0, 1 );

  /* Could create the image */
  if ( bitmap )
  {
    lockArea.Point1.X = 0;
    lockArea.Point1.Y = 0;
    lockArea.Point2.X = frameSize.X;
    lockArea.Point2.Y = frameSize.Y;
    
    lock = EwLockBitmap( bitmap, 0, lockArea, 0, 1 );

    /* Make a one-row-high sample array that will go away when done with image */
    buffer = (*cinfo.mem->alloc_sarray)((j_common_ptr)&cinfo, JPOOL_IMAGE, 
               cinfo.output_width * cinfo.output_components, 1 );

    /* As long as any scan lines to process ... */
    while ( cinfo.output_scanline < cinfo.output_height )
    {
      unsigned int   x;
      unsigned char* sample = buffer[0];
      unsigned int*  dest   = (unsigned int*)((char*)lock->Pixel1 + 
                               cinfo.output_scanline * lock->Pitch1Y );

      jpeg_read_scanlines( &cinfo, buffer, 1 );

      /* Transfer the samples into the bitmap pixel row */
      for ( x = 0; x < cinfo.output_width; x++ )
      {
        /* Get the RGB value from the JPEG decoder and arrange the 'red',
           'green', 'blue' channels at the right bit offset position */
        unsigned int red   = *sample++ << EW_COLOR_CHANNEL_BIT_OFFSET_RED;
        unsigned int green = *sample++ << EW_COLOR_CHANNEL_BIT_OFFSET_GREEN;
        unsigned int blue  = *sample++ << EW_COLOR_CHANNEL_BIT_OFFSET_BLUE;
        
        /* Store the pixel data in the bitmap memory */
        *dest++ = red | green | blue | ( 0xFF << EW_COLOR_CHANNEL_BIT_OFFSET_ALPHA );
      }
    }

    /* Don't forget to unlock the bitmap */
    EwUnlockBitmap( lock );
  }

  /* Step 7: Finish decompression */
  jpeg_finish_decompress( &cinfo );

  /* Step 8: Release JPEG decompression object */
  jpeg_destroy_decompress( &cinfo );

  /* After finish_decompress, we can close the input file. */
  fclose( infile );

  /* Release temporary memory */
  free( name );

  /* all ok */
  return bitmap;
}

Extern Bitmap and screen rotation

With the attribute ScreenOrientation you have the possibility to configure your project to be prepared for devices with the LCD installed in an orientation different to the normal with the GUI coordinate origin 0,0 found at the LCD origin. If you intend to use Extern Bitmap in such configured device, please consider that the rotation affects how pixel are stored and accessed within a bitmap (surface).

The GUI application thinks always in logical screen coordinates, which are relative to the top-left corner of the GUI. In turn, internally, when rotation is used (attribute ScreenOrientation is not Normal), the bitmaps store the pixel corresponding to the specified rotation.

Embedded Wizard takes care of the right coordinate conversion wherever you access and display images. Similarly, all Bitmap resources are generated in the corresponding rotation format. In other words, usually you don't need to worry about the mechanisms. This however is not the case, when you intend to lock and access the bitmap by yourself.

In this case you have to convert between the logical GUI coordinates and the real surface coordinates. For example, with the 270 degree rotation (attribute ScreenOrientation is set Rotated_270) you have to calculate with exchanged bitmap width and height. Additionally, the X and Y coordinates need an adjustment.

The following is a code snippet demonstrating how the Graphics Engine converts internally between the logical GUI coordinates and the real surface coordinates to fill a rectangular area. You see there following code for the 270 degree rotation case:

#if EW_SURFACE_ROTATION == 270
  FillRectangle( dstBitmap, Y, Width - X, Height, Width );
#endif

In turn, the following code demonstrates the same operation within a device configured with 0 degree rotation (attribute ScreenOrientation is set Normal):

#if EW_SURFACE_ROTATION == 0
  FillRectangle( dstBitmap, X, Y, Width, Height );
#endif

As you see, in case of 270 degree rotation the resulting surface X coordinate is equal to the GUI logical Y coordinate while the surface Y coordinate is equal to the real width of the surface minus GUI logical X coordinate. The width of the area affected in the surface is equal to the height of the area seen in GUI logical coordinates. The height of the area affected in the surface is equal to the width of the area seen in GUI logical coordinates.

Thus when you lock and modify the bitmap memory as described in section Function EwLoadExternBitmap(), you should take care of the right coordinate conversion. If necessary, you can evaluate the ANSI-C macro EW_SURFACE_ROTATION and so support the various rotation cases within your code.

Reload the content of Extern Bitmap

Under normal circumstances, the Extern Bitmap object updates its content only when new value is assigned to its property Name. As long as the value of the property Name doesn't change, the Extern Bitmap object is assumed as containing the same image. Accordingly, the bitmap returned in the preceding EwLoadExternBitmap() doesn't change.

In special application cases, however, the image content represented by an Extern Bitmap object may change without the property Name being explicitly modified. Imagine an application intended to display an image received over the network. Now let's assume, the server providing the original image is updated and the image content changes. From the application point of view, the image is still identified by the same URL, so the value of the property Name remains unchanged. The content on the server, however, is modified.

In such case the application has to reload the image again obtaining so its newest version. This operation has to be triggered by the method Reload(). When you invoke the method, the Extern Bitmap object will call the EwLoadExternBitmap() function requesting so the new version of the affected image.

Accordingly, when the server notifies your application about the alternation of the image content, you have to feed the notification to the GUI application permitting it to trigger the Reload() method of the affected Extern Bitmap object. The simplest approach to feed such notifications is to use the System Event mechanisms and the corresponding System Event Handler.

Extern Bitmap and Prototyping

Since the implementation of the above described interface is very particular to every application case and every target device, this interface is per default not available when you are running the application in the Prototyper or Composer window. This has as consequence that when you trigger an Extern Bitmap object to load the image content, the following runtime error is reported:

You have two possibilities how to deal with this situation:

Option 1: You can use $if .. $endif compiler directives to exclude the affected code when running the application in the prototyping environment. For example, you prevent the property Name of the Extern Bitmap object from being modified if the code is not compiled for the target system:

// The string identifying the image content to load
var string name = ...

$if $prototyper
  // In the prototyping environment don't touch the Extern Bitmap
  // object. You can just report a 'trace' message to see, that the
  // operation is performed
  trace "Trying to load image '" + name "'";
$else
  // When generating code for the target system, assign the name to
  // the Extern Bitmap object as expected.
  ExternBitmapObject.Name = name;
$endif

Option 2: You enhance the prototyping environment by the missing interface implementation. Embedded Wizard supports for such application cases a technique called intrinsic modules. Technically seen, an intrinsic module is an ordinary Microsoft Windows DLL (dynamic loadable library). You develop such module by using the Microsoft Visual Studio. Once you are finished, you copy the module into your project folder. Afterwards when you start the prototyping environment, Embedded Wizard will load the module and provide its functionality for the tested application. How intrinsic modules are implemented is described in the chapter Implementing Prototyper intrinsics.

Extern Bitmap and WebGL (JavaScript) Platform Package

The WebGL Platform Package contains already an implementation of the above described interface. This implementation takes care of the loading of the requested image contents as PNG, JPG, etc. files from URLs passed in the parameter aName. The loading operation occurs asynchronously. As soon as the requested image contents are available, the Platform Package notifies automatically the affected Extern Bitmap object and updates all associated image views.

This has the consequence, that just after changing the property Name of the Extern Bitmap object, the old image content is discarded leaving the Extern Bitmap object temporarily without any content. In the meantime the affected Extern Bitmap object is considered as being empty.

Please note, a customer specific adaptation of the EwLoadExternBitmap() interface (e.g. to use contents rendered dynamically by a third-party application) is actually not possible with the WebGL Platform Package. All image contents are addressed by URLs only.