Image manipulation library

         File: LibImageManip.zip
       Author: Edmund Vermeulen <edmundv@xs4all.nl>
      Release: 1.1.0 (Jan 26th 2000)
Compatibility: BeOS R4 for PowerPC and Intel
     Location: contrib/libraries
  Description: Image manipulation library
        Notes: Public domain



Contents

Introduction

LibImageManip is my attempt at creating a library for image manipulation add-ons that is simple to use. It is modelled after, and based on, the datatypes library (now the translation kit) by Jon Watte.

The library basically supports two kinds of add-ons, known as manipulators and converters.

Manipulators
A manipulator add-on takes a source bitmap and then manipulates it any way it wants. Examples would be: gamma correct, twirl, ripple, oil paint, negative, flip horizontal, etc.
Converters
A converter add-on takes a source bitmap and then converts it to a new bitmap. Examples would be: scale, dither to 8-bit, rotate 90 degrees, crop, etc. Basically anything that needs a different size or color depth.

The library and its add-on interface are designed to be as simple as possible in order to encourage anyone to create add-ons or use the library in his/her applications. The library is completely free and comes with full source code.



The bitmap accessor class

The image manipulation library uses a proxy class for accessing bitmaps. This has several advantages over directly using the BBitmap class:

The proxy class is an abstract base class with the following interface:

  class BitmapAccessor
  {
  public:
      virtual ~BitmapAccessor();
      virtual bool IsValid() = 0;
      virtual bool CreateBitmap(BRect bounds, color_space space) = 0;
      virtual BRect Bounds() = 0;
      virtual color_space ColorSpace() = 0;
      virtual float BytesPerPixel(); 
      virtual void *AccessBits(BRect area, int32 *rowBytes) = 0;
      virtual void BitsNotChanged() = 0;
  };

The IsValid(), Bounds(), and ColorSpace() functions work the same as the equivalent functions in the BBitmap class. Beware that Bounds() may return a rectangle that is not positioned at (0, 0).

The CreateBitmap() function is called from within the Convert() function by a converter add-on to create the destination bitmap.

The BytesPerPixel() function is used to get the number of bytes in a single pixel. If the pixel size is larger than you would expect then you should simply skip the extra bytes at the end to get to the next pixel. This can be the case for 'multi-channel' bitmaps, where several channels of data are interleaved. For example, when accessing only the blue part of a 32-bit bitmap as if it was an 8-bit grayscale bitmap. For monochrome bitmaps the number of bytes per pixel is 1/8th. These bitmaps are special. For instance, you can only access the bits on their natural alignment, and not in the middle of a chunk.

With the AccessBits() function you gain access to the raw data of a certain area of the bitmap. The number of bytes per row is returned in the rowBytes variable. You can use this number to skip to the next row of pixels if you accessed more then one row. The pointer returned by AccessBits() will remain valid until another call to AccessBits() or to the destructor is made. For efficienscy reasons you should keep the requested area small.



The BBitmapAccessor class

For applications there is a class for accessing BBitmaps implemented in the library. It is called BBitmapAccessor, and besides the normal bitmap accessor functions, it has the following extra functions:

  class BBitmapAccessor : public BitmapAccessor
  {
  public:
     // Constructor
     BBitmapAccessor(BBitmap *bitmap = NULL, const BRect *section = NULL);

     // Overriden BitmapAccessor functions
     ...

     // Get pointer to the BBitmap
     virtual BBitmap *Bitmap() const;

     // Get/set if the BBitmap should be deleted at destruction time
     virtual bool Dispose() const;
     virtual void SetDispose(bool flag);

     // Set invokers for automatically sending messages when a bitmap
     // is created and/or when it is updated
     virtual void SetInvokers(BInvoker *bitmapCreated, BInvoker *bitmapUpdated);

  private:
     ...
};

The BBitmap to accesss can be specified in the constructor. Optionally, access can be restricted to a given rectangular section. By default, the ownership of the BBitmap stays with the caller. If you want the BBitmapAccessor object to delete the bitmap for you then you should call SetDispose(true) on it. If a new BBitmap is created through CreateBitmap() then the ownership initially lies with the BBitmapAccessor object. Call SetDispose(false) on it if you don't want it to be deleted for you.

You can set invokers for automatically sending messages when a bitmap is created and/or when it is updated. You will be notified by the invoker's message with some extra data added to it. This will be respectively the newly created bitmap pointer, or a rectangle of the updated area. The data can be extracted from the message as follows:

  BBitmap *new_bitmap;
  msg->FindPointer("bitmap", reinterpret_cast(&new_bitmap));

  BRect update_rect;
  msg->FindRect("rect", &update_rect);

The invokers will automatically be deleted by the BBitmapAccessor object.



The add-on interface

Here is a list of all exported data and functions of an image manipulation add-on.

  const char addonName[];  /* required, C string, ex "Gamma Correct" */
  const char addonInfo[];  /* required, descriptive C string, ex "Makes images brighter. Written by Slartibardfast." */
  const char addonCategory[]; /* optional, C string, ex "Color" */
  int32 addonVersion;  /* required, integer, ex 100 */

  status_t Manipulate(
      BitmapAccessor *sourceBitmap,
      BMessage *ioExtension,        /* can be NULL */
      bool checkOnly);

  status_t Convert(
      BitmapAccessor *sourceBitmap,
      BitmapAccessor *destBitmap,   /* call CreateBitmap() on this */
      BMessage *ioExtension,        /* can be NULL */
      bool checkOnly);

  status_t MakeConfig(  /* optional */
      BMessage *ioExtension,        /* can be NULL */
      BView **outView);

  status_t GetConfigMessage(  /* optional */
      BMessage *ioExtension,
      BMessage *ioCapability);

The addonName, addonInfo, addonCategory, and addonVersion are exported data that contain user accessable information about the add-on.

The Manipulate() and Convert() functions are where the real work is done. Depending on which function an add-on exports, it is considered to be an image manipulator or image converter. Both functions can be called in normal or in 'check-only' mode. This last mode is used to ask an add-on if it supports a certain source bitmap and io extension. The add-on should return B_NOT_ALLOWED if it doesn't.

Both the Manipulate() and Convert() functions take a pointer to a source bitmap accessor. The Convert() function also take a pointer to an empty bitmap accessor object on which it will call CreateBitmap() to create the destination bitmap. The ioExtension argument is optional, and may be ignored by the add-on.

The ioExtension message can be used for passing add-on specific configuration settings as explained below. It can also be used to, for example, ask the add-on to only affect a certain rectangle instead of the whole bitmap. Some standard io extensions are defined for this purpose. The add-on should add the io extensions that it supports to the ioCapability message in its GetConfigMessage() function.

The last two functions are optional. MakeConfig() allows the add-on to create a BView with controls to let the user configure the add-on's settings. GetConfigMessage() is used to get the current settings and supported capabilities from the add-on. The settings are added to the ioExtension message. This message can be stored and passed back to the add-on through the Manipulate() or Convert() functions. The capabilities are added as name and type code pairs to the ioCapability message. This can be used by an application to check if an add-on supports a certain io extension.



The application interface

Here is a list of the functions that an application can use in the image manipulation library.

  /* Get the current version of the library and the minimum
     version with which it is still compatible */
  const char *
  Image_Version(
      int32 *curVersion,             /* will receive the current version */
      int32 *minVersion);            /* will receive the minimum version */

  /* Initialize the library before usage */
  status_t
  Image_Init(
      const char *loadPath);         /* NULL for the default */

  /* Shutdown the library after usage */
  status_t
  Image_Shutdown();

  /* Get all image manipulators that support a given source bitmap
     and io extension */
  status_t
  Image_GetManipulators(
      BitmapAccessor *sourceBitmap,  /* NULL to get all manipulators */
      BMessage *ioExtension,         /* can be NULL */
      image_addon_id **outList,      /* call delete[] on it when done */
      int32 *outCount);              /* will receive amount in list */

  /* Get all image converters that support a given source bitmap
     and io extension */
  status_t
  Image_GetConverters(
      BitmapAccessor *sourceBitmap,  /* NULL to get all converters */
      BMessage *ioExtension,         /* can be NULL */
      image_addon_id **outList,      /* call delete[] on it when done */
      int32 *outCount);              /* will receive amount in list */

  /* Get info on an image manipulator or image converter add-on */
  status_t
  Image_GetAddonInfo(
      image_addon_id imageAddon,
      const char **addonName,        /* will receive pointer to the name */
      const char **addonInfo,        /* will receive pointer to the info */
      const char **addonCategory     /* will receive pointer to the category */
      int32 *addonVersion);          /* will receive the version */

  /* Let an add-on manipulate a bitmap */
  status_t
  Image_Manipulate(
      image_addon_id imageManipulator,
      BitmapAccessor *sourceBitmap,
      BMessage *ioExtension,         /* can be NULL */
      bool checkOnly = false);

  /* Let an add-on convert a bitmap to another bitmap */
  status_t
  Image_Convert(
      image_addon_id imageConverter,
      BitmapAccessor *sourceBitmap,
      BitmapAccessor *destBitmap,    /* will be called CreateBitmap() on */
      BMessage *ioExtension,         /* can be NULL */
      bool checkOnly = false);

  /* Let an add-on make a BView that allows the user to configure it */
  status_t
  Image_MakeConfigurationView(
      image_addon_id imageAddon,
      BMessage *ioExtension,         /* can be NULL */
      BView **configView);           /* will receive pointer to the new BView */

  /* Get configuration and capabilities from an add-on */
  status_t
  Image_GetConfigurationMessage(
      image_addon_id imageAddon,
      BMessage *ioExtension,         /* message to add config info to */
      BMessage *ioCapability);       /* message to add capability info to */

  /* Create a new BBitmapAccessor object; mimics the constructor */
  BBitmapAccessor *
  Image_CreateBBitmapAccessor(
      BBitmap *bitmap = NULL,
      const BRect *section = NULL);

To use the library in your own applications you have two options:

Normal linkage
Include the file 'ImageManip.h', and link directly against the library. Just add the file 'libimagemanip.so' to your project by dropping it on the BeIDE.
Weak linkage
This allows applications to run even if libimagemanip.so isn't installed. Add the file 'ImportImageManip.cpp' to your application's project. Be careful to define the symbol _IMPEXP_IMAGEMANIP to nothing before including any of the library's header files. With weak linkage, you have to use the Image_CreateBBitmapAccessor() function to create new BBitmapAccessor objects.


Standard io extensions

Name Type Description
"color_space" B_INT32_TYPE If possible, create the new bitmap with this color space when you call CreateBitmap().
"selection_rect" B_RECT_TYPE Selection rectangle; the pixels that make up the edge of the rectangle are considered included in the rectangle.
"selection_map" B_POINTER_TYPE Selection bitmap; the pointer is to a BitmapAccessor object which defines an "alpha" channel to determine selected-ness.
"use_alpha" B_BOOL_TYPE Use the alpha channel for determining selected-ness (for B_RGBA32 and friends).
"progress_invoker" B_POINTER_TYPE Pointer to a BInvoker for sending progress messages with the amount of completion added. E.g. AddFloat("completion", 0.5) for 50%.



History

Release 1.1.0 (Jan 26th 2000)

Release 1.0.0 (Nov 18th 1999)

Release 0.6.1 (Jan 4th, 1999)

Release 0.6.0 (Aug 23th, 1998)

Release 0.5.0 (Aug 9th, 1998)

Release 0.4.0 (Jul 13th, 1998)

Release 0.3.0 (Jul 6th, 1998)

Release 0.2.0 (Jun 22nd, 1998)



Installation

To be able to use the library, you should copy the file 'libimagemanip.so' to the folder 'boot/home/config/lib'. You also need some add-ons in the folder 'boot/home/config/add-ons/ImageManip'.



Public domain

The image manipulation library was written by Edmund Vermeulen, based on the original code of the datatypes library written by Jon Watte.

The library, its example application, and the example add-ons are public domain. There are no restrictions on distribution or usage.



Back to Edmund's home page