CPC Rapid Deployment API
VERSION 5.2

[The following sections are generated directly from the source file: RapidCpc.h
Revision: 1.10 Date: 2005/04/27 18:33:35
©1996-2005 Cartesian Products, Inc. All rights reserved.]

The Cartesian Perceptual Compression (CPC) method and its implementation are designed to be inter-operable across a wide spectrum of application environments, ranging from standalone office equipment to Internet Browser add-on modules. For most applications, however, the core API provides more freedom than is necessary, thereby requiring greater complexity in the application. To facilitate rapid application development, an alternative API, known as the Rapid Deployment API, is provided. Although the Rapid Deployment API does not have the flexibility of the core API, it is sufficient for the overwhelming majority of applications, providing a fast path to incorporating CPC compression into existing applications. This document describes the Rapid Deployment Application Programming Interface to the CPC programming library.

Note: The portion of the API described in this document requires the use of files for the underlying storage of the raw CPC data. The document, Rapid Deployment Data Streams, describes an extension of the API, which allows an application to utilize arbitray storage mechanisms for the raw CPC data.


1. Architecture

The CPC method is a document-oriented compression method, rather than a page-oriented compression method. A group of page images is compressed into a single data stream, known as a document. Unlike page-oriented methods such as TIFF or GIF, there is no finer partitioning of the data stream; information about separate pages is freely interspersed within the stream.

The Rapid Deployment API provides two objects for interacting with documents:

An application compresses images by attaching a CpcEncoder to an open file, writing page images to the encoder, and finally, detaching the encoder from the file. An application decompresses images by attaching a CpcDecoder to an open file, reading page images from the decoder, and finally, detaching the decoder from the file.


2. Pattern Geometry

In CPC, image patterns are described in terms of an integral cartesian coordinate system in which the direction of the y-axis is inverted: positive row increments move across the pattern from top to bottom. This section provides definitions for the basic data types and coordinate system used by CPC.

2.1. Coordinates

A point on the image plane is represented by an integral row coordinate (ImRow) and an integral column coordinate (ImCol). To conserve space, CPC stores coordinate indices in a 16-bit short-word, allowing for a maximal image dimension of 65,536. (Negative coordinates are not used in the Rapid Deployment API.)

Type Definition: ImRow
Specifies a row coordinate in CPC.
typedef unsigned short ImRow;

Type Definition: ImCol
Specifies a column coordinate in CPC.
typedef unsigned short ImCol;

2.2. Dimensions

The dimensions (ImDim) of a pattern define the size of the pattern's bounding box.

Type Definition: ImDim
Describes the dimensions of a pattern. The field num_rows specifies the pattern height (in pixels); the field num_cols specifies the pattern width (in pixels).
typedef struct ImDim { 
  ImRow num_rows; ImCol num_cols;
} ImDim;

2.3. Resolution

The resolution (ImResolution) of an image defines the correlation between image pixels and physical size. This information is necessary to display or print an image at the proper physical size. Image resolutions are specified in pixels per inch.

Type Definition: ImResolution
Specifies the resolution of an image. Separate resolutions are specified for the x and y axes. The field xDpi specifies the resolution of the x-axis in pixels per inch; the field yDpi specifies the resolution of the y-axis in pixels per inch. If the resolution of an axis is not known, the corresponding field (xDpi or yDpi) is set to zero.
typedef struct ImResolution { 
  float xDpi, yDpi; 
} ImResolution;


3. Image Bitmaps

In the Rapid Deployment API, all page images are described in a representational format known as a bit-map. The bit-map represents an image as a two-dimensional array of bits, where each bit represents the color of a single pixel in the image. A black pixel is represented by a bit value of 1; a white pixel is represented by a bit value of 0.

Multiple pixels are packed together, as densely as possible, into a single word of memory. Within a long-word, bitmap data is stored in most-significant to least-significant (big-endian) order. That is, column 0 is the most significant bit of the long-word; column 1 is the next most significant bit, etc.

Bit-maps are organized into rows of pixels. For efficiency reasons, it is useful to insure that each row of the map begins on a long-word boundary. Hence, the width of a row is rounded up to a multiple of the number of bits in a long-word (i.e., 32). A bit-map, therefore, has two dimensions:

Type Definition: ImBitMap
Describes the bit-map representation of a pattern. The image dimensions of the pattern are stored in img_dim, and the memory dimensions of the pattern are stored in mem_dim. pixels points to the memory buffer that stores the pattern bit-map.
Note: The memory width is always a multiple of the number of bits in a long-word, and hence, each image row in pixels starts on a long-word boundary.
typedef struct ImBitMap { 
  ImDim img_dim, mem_dim; unsigned long *pixels; 
} ImBitMap;

3.1. Creating a Bit-Map

The following function is used to create a bitmap. When the application is done with the bit-map, it should call ibm_destroy to deallocate it.

Function Definition: ibm_create
Create a bitmap with the image dimensions, imgDim. If initializePixels is non-zero, the pixels of the bitmap are initialized to zero (white). Otherwise, the pixels are not initialized.
Returns a pointer to the bitmap, or 0 if the bitmap could not be allocated.
ImBitMap *ibm_create(ImDim imgDim, unsigned initializePixels);

3.2. Accessing the rows of a Bit-Map

Once a bitmap has been created, the following convenience function can be used to access a specific row of pixels within it. As noted earlier, within a row, the pixels are stored in big-endian order.

Function Definition: ibm_getRow
Returns a pointer to the pixel longword that contains column 0 of the row, rowNum, within the bit-map, ibm. Rows are numbered from zero.
Warning: If rowNum is greater than or equal to the height of the bit-map, the returned pointer is not valid.
unsigned long *ibm_getRow(ImBitMap *ibm, unsigned rowNum);

3.3. Destroying a Bit-Map

When the application is done using a bit-map, it should destroy it using the following interface.

Function Definition: ibm_destroy
Destroy the bitmap, ibm, de-allocating its memory.
Warning: On return from this function, ibm is no longer valid, and the application should not use it on any subsequent interaction with the CPC library.
void ibm_destroy(ImBitMap *ibm);


4. The CPC Encoder

Applications that wish to compress image data use the CpcEncoder object of the Rapid Deployment API. The basic operation is as follows:

Opaque Type: CpcEncoder
The opaque data type used to represent a CPC encoder.
typedef struct CpcEncoder CpcEncoder;

4.1. Creating an Encoder

The first step in encoding a document is to create the CpcEncoder and attach it to an open file. The Rapid Deployment API supports two variants of the CPC format: CPC-Normal and CPC-Progressive. The CPC-Progressive variant sacrifices a small amount of compression (on the order of 1 percent) in order to provide better interactive feedback when decoding data over a slow connection such as a telephone modem. Although the Rapid Deployment API can decode either variant, the API does not support the interfaces necessary to receive the progressive feedback, so its use within this API is not recommended.

Note: When the application is done with the encoder, it should call cpcEnc_destroy to deallocate it.

Function Definition: cpcEnc_createFromFile
Create a CPC encoder that sends its compressed CPC data to the file, sink, starting at the file's current seek position. If progressive is non-zero, the document is encoded using the CPC-Progressive format. Otherwise, it is encoded using the CPC-Normal format.
Returns a pointer to the encoder, or 0 if the encoder could not be created. The only reason for failure is that memory could not be allocated.
Note: sink must be a seekable file (i.e., it must not be a pipe), and it must be opened in binary mode.
CpcEncoder *cpcEnc_createFromFile(FILE *sink, unsigned progressive);

4.2. Adding Pages to the Document

Once the encoder is created, the application passes each page of the document to the following interface. The order in which pages are added determines the order of pages in the compressed document.

Function Definition: cpcEnc_addPage
Add the page described by ibm as the next page in the document that cpc is encoding.
void cpcEnc_addPage(CpcEncoder *cpc, ImBitMap *ibm);

4.3. Destroying the Encoder

Once all of the pages have been added, the application completes the compression sequence by destroying the encoder, using the following interface.

Function Definition: cpcEnc_destroy
Flush all document data to the output file and destroy the encoder, cpc. If closeOutput is non-zero, the output file is also closed. Otherwise, the encoder is detached from the output file, and on return, the output file's seek pointer is positioned immediately after the compressed document data. (On an error, the position of the output file's seek pointer is undefined.)
Note: If an application is using Rapid Deployment Data Streams, the closeOutput parameter determines whether or not the output Data Stream is also closed.
Returns 0 if the encoder successfully compressed the document. Otherwise, returns a pointer to a zero-terminated ASCII string describing the nature of the error.
Warning: On return from this function, cpc is no longer valid, and the application should not use it on any subsequent interaction with the CPC library.
Warning: The returned string is owned by the CPC library. It should not be modified or deallocated by the application.
char const *cpcEnc_destroy(CpcEncoder *cpc, unsigned closeOutput);

4.4. Encoder Example

The following example demonstrates encoding a list of bit-maps, described by an array, pages, and the number of elements in the array, pageCnt. The data is written to the file, out.cpi.

Note: This example is for expository purposes only; in a real-world application, it would be inefficient to buffer all of the page bitmaps for a document.

char const *Encode(ImBitMap *pages[], unsigned pageCnt)
{
  unsigned i; CpcEncoder *cpc; FILE *fp;
  fp = fopen("out.cpi", "wb");
  if(!fp) { return "Unable to create output file"; }
 
  cpc = cpcEnc_createFromFile(fp, 0/*CPC-Normal*/);
  if(!cpc) { fclose(fp); return "Unable to create decoder"; }

  for(i=0; i<pageCnt; i++) { cpcEnc_addPage(cpc, pages[i]); }
  return cpcEnc_destroy(cpc, 1/*closeOutput*/);
}


5. The CPC Decoder

Applications that wish to decompress image data use the CpcDecoder object of the Rapid Deployment API. The basic operation is as follows:

Opaque Type: CpcDecoder
The opaque data type used to represent a CPC decoder.
typedef struct CpcDecoder CpcDecoder;

5.1. Creating a Decoder

The first step in decoding a document is to create the CpcDecoder using the following interface. When the application is done with the document, it should call cpcDec_destroy to deallocate the decoder.

Function Definition: cpcDec_createFromFile
Create a CPC decoder that reads its compressed CPC data from the file, data, starting at the file's current seek position. If sequential is non-zero, the decoder is configured for sequential access to the pages. Otherwise, the decoder is configured for random access. (Random access uses an additional 750k of memory.)
Returns a pointer to the decoder, or 0 if the decoder could not be created. The only reason for failure is that memory could not be allocated.
Note: data must be a seekable file (i.e., it must not be a pipe), and it must be opened in binary mode.
CpcDecoder *cpcDec_createFromFile(FILE *data, unsigned sequential);

5.2. Determining the Page Count

Once the decoder is created, the application can determine the number of pages in the document using the following interface.

Function Definition: cpcDec_getPageCount
Returns the number of pages contained in the document that the decoder, cpc, is reading.
unsigned cpcDec_getPageCount(CpcDecoder *cpc);

5.3. Retrieving Page Bit-Maps

The application can retrieve the individual page bit-maps that comprise the document using the following function.

Function Definition: cpcDec_getPage
Retrieve the bit-map for page, pageNum, from the decoder, cpc. Pages are numbered from zero.
Returns a pointer to the bitmap, or 0 if an error occurred. The caller is responsible for deallocating the bitmap (using ibm_destroy) when it is done with it.
ImBitMap *cpcDec_getPage(CpcDecoder *cpc, unsigned pageNum);

5.4. Determining Page Resolution

The application can retrieve the image resolution of a particular page using the following function.

Function Definition: cpcDec_getPageRes
Retrieve the image resolution for page, pageNum, from the decoder, cpc. The resolution is returned in the output parameter, res. Pages are numbered from zero.
void cpcDec_getPageRes(CpcDecoder *cpc, unsigned pageNum, ImResolution *res);

5.5. Querying the Error State

At any time, the application can query the error state of the decoder.

Function Definition: cpcDec_getError
Returns 0 if the decoder, cpc, has not encountered any errors. Otherwise, returns a pointer to a zero-terminated ASCII string describing the nature of the error.
Warning: The returned string is owned by the CPC library. It should not be modified or deallocated by the application.
char const *cpcDec_getError(CpcDecoder *cpc);

5.6. Destroying the Decoder

Once the application has completed processing the document, it should destroy the decoder.

Function Definition: cpcDec_destroy
Closes the CPC decoder, cpc. If closeInput is non-zero, the underlying input file will also be closed. Otherwise, the decoder is detached from the input file. On return, the position of the input file's seek pointer is undefined.
Note: If an application is using Rapid Deployment Data Streams, the closeInput parameter determines whether or not the input Data Stream is also closed.
Returns 0 if the decoder has not encountered any errors. Otherwise, returns a pointer to a zero-terminated ASCII string describing the nature of the error.
Warning: On return from this function, cpc is no longer valid, and the application should not use it on any subsequent interaction with the CPC library.
Warning: The returned string is owned by the CPC library. It should not be modified or deallocated by the application.
char const *cpcDec_destroy(CpcDecoder *cpc, unsigned closeInput);

5.7. Decoder Example

The following example demonstrates decoding each of the page bitmaps from a cpc document stored in the file, fp.

char const *Decode(FILE *fp)
{
  unsigned i, pageCnt; CpcDecoder *cpc;
  cpc = cpcDec_createFromFile(fp, 1/*sequential*/);
  if(!cpc) { return "Unable to create decoder"; }

  for(i=0, pageCnt=cpcDec_getPageCount(cpc); i<pageCount; i++) { 
    ImBitMap *ibm = cpcDec_getPage(cpc,i); 
    if(!ibm) { break; }
    ibm_destroy(ibm);   
  }
  return cpcDec_destroy(cpc, 0/*do not close file*/);
}


6. Compilation

In order to use the Rapid Deployment API, the application must include the file RapidCpc.h, and link with the static library RapidCpc.lib. The library is a C-language library. C++ applications should surround the include with an extern "C" environment.

extern "C" {
# include "RapidCpc.h"
};


7. Memory Allocation

By default, the CPC library will use its own internal memory allocator for memory allocations and deallocations. (The library uses malloc on Unix systems, and GlobalAlloc on Win32 systems.) The application may substitute its own allocator by initializing a CpcMemAllocator data structure and passing it to the CPC library, via cpcMem_setAllocator, prior to calling any other CPC library function. The semantics of the three CpcMemAllocator interfaces are identical to the ANSI C functions malloc, free, and realloc. All threads within a process must use the same memory allocator and the allocator must be thread-safe.

Type Definition: CpcMemAllocator
Defines the functions to use for memory management. Allocate has the same semantics as the ANSI C malloc function. Reallocate has the same semantics as the ANSI C realloc function. Free has the same semantics as the ANSI C free function.
typedef struct CpcMemAllocator {
  void *(*Allocate)(unsigned long numBytes);
  void *(*Reallocate)(void *mem, unsigned long numBytes);
  void (*Free)(void *ptr);
} CpcMemAllocator;

The following interface is used to set the memory allocator for the calling process.

Function Definition: cpcMem_setAllocator
Set the CPC memory allocator to the allocator, cpcMem. The CPC library copies the CpcMemAllocator, so the application may pass a pointer to temporary memory.
Warning: This function, if it is called, must be called prior to calling any other CPC library functions.
void cpcMem_setAllocator(CpcMemAllocator *cpcMem);


8. Multi-Threading

The Rapid Deployment API does not currently support multi-threaded applications, although the core library can be used in multi-threaded applications under certain circumstances. For further information, contact Cartesian Products.


9. Binary Mode

All FILE pointers passed to the Rapid Deployment API must be opened in binary mode. This is done by appending the character, 'b', to the second argument of the fopen function (e.g., fopen("x", "wb")).


Index



THE FINE PRINT (regarding copyrights and trademarks)

Cartesian Products, Inc.
cpi@cartesianinc.com