blob: 2ff8f023c319066424606a367fce5f584ae15048 [file] [log] [blame]
// ==========================================================
// Wireless Bitmap Format Loader and Writer
//
// Design and implementation by
// - Hervé Drolon <drolon@infonie.fr>
//
// This file is part of FreeImage 3
//
// COVERED CODE IS PROVIDED UNDER THIS LICENSE ON AN "AS IS" BASIS, WITHOUT WARRANTY
// OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, WITHOUT LIMITATION, WARRANTIES
// THAT THE COVERED CODE IS FREE OF DEFECTS, MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE
// OR NON-INFRINGING. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE COVERED
// CODE IS WITH YOU. SHOULD ANY COVERED CODE PROVE DEFECTIVE IN ANY RESPECT, YOU (NOT
// THE INITIAL DEVELOPER OR ANY OTHER CONTRIBUTOR) ASSUME THE COST OF ANY NECESSARY
// SERVICING, REPAIR OR CORRECTION. THIS DISCLAIMER OF WARRANTY CONSTITUTES AN ESSENTIAL
// PART OF THIS LICENSE. NO USE OF ANY COVERED CODE IS AUTHORIZED HEREUNDER EXCEPT UNDER
// THIS DISCLAIMER.
//
// Use at your own risk!
// ==========================================================
#include "FreeImage.h"
#include "Utilities.h"
// ----------------------------------------------------------
// Wireless Bitmap Format
// ----------------------
// The WBMP format enables graphical information to be sent to a variety of handsets.
// The WBMP format is terminal independent and describes only graphical information.
// IMPLEMENTATION NOTES:
// ------------------------
// The WBMP format is configured according to a type field value (TypeField below),
// which maps to all relevant image encoding information, such as:
// · Pixel organisation and encoding
// · Palette organisation and encoding
// · Compression characteristics
// · Animation encoding
// For each TypeField value, all relevant image characteristics are
// fully specified as part of the WAP documentation.
// Currently, a simple compact, monochrome image format is defined
// within the WBMP type space :
//
// Image Type Identifier, multi-byte integer 0
// Image Format description 0 B/W, no compression
// -------------------------------------------------------------------------------
// WBMP Header
#ifdef _WIN32
#pragma pack(push, 1)
#else
#pragma pack(1)
#endif
typedef struct tagWBMPHEADER {
WORD TypeField; // Image type identifier of multi-byte length
BYTE FixHeaderField; // Octet of general header information
BYTE ExtHeaderFields; // Zero or more extension header fields
WORD Width; // Multi-byte width field
WORD Height; // Multi-byte height field
} WBMPHEADER;
#ifdef _WIN32
#pragma pack(pop)
#else
#pragma pack()
#endif
// The extension headers may be of type binary 00 through binary 11, defined as follows.
// - Type 00 indicates a multi-byte bitfield used to specify additional header information.
// The first bit is set if a type 00, extension header is set if more data follows.
// The other bits are reserved for future use.
// - Type 01 - reserved for future use.
// - Type 10 - reserved for future use.
// - Type 11 indicates a sequence of parameter/value pairs. These can be used for
// optimisations and special purpose extensions, eg, animation image formats.
// The parameter size tells the length (1-8 bytes) of the following parameter name.
// The value size gives the length (1-16 bytes) of the following parameter value.
// The concatenation flag indicates whether another parameter/value pair will follow
// after reading the specified bytes of data.
// ==========================================================
// Internal functions
// ==========================================================
static DWORD
multiByteRead(FreeImageIO *io, fi_handle handle) {
// Multi-byte encoding / decoding
// -------------------------------
// A multi-byte integer consists of a series of octets, where the most significant bit
// is the continuation flag, and the remaining seven bits are a scalar value.
// The continuation flag is used to indicate that an octet is not the end of the multi-byte
// sequence.
DWORD Out = 0;
BYTE In = 0;
while (io->read_proc(&In, 1, 1, handle)) {
Out += (In & 0x7F);
if ((In & 0x80) == 0x00)
break;
Out <<= 7;
}
return Out;
}
static void
multiByteWrite(FreeImageIO *io, fi_handle handle, DWORD In) {
BYTE Out, k = 1;
while (In & (0x7F << 7*k))
k++;
while (k > 1) {
k--;
Out = (BYTE)(0x80 | (In >> 7*k) & 0xFF);
io->write_proc(&Out, 1, 1, handle);
}
Out = (BYTE)(In & 0x7F);
io->write_proc(&Out, 1, 1, handle);
}
static void
readExtHeader(FreeImageIO *io, fi_handle handle, BYTE b) {
// Extension header fields
// ------------------------
// Read the extension header fields
// (since we don't use them for the moment, we skip them).
switch (b & 0x60) {
// Type 00: read multi-byte bitfield
case 0x00:
{
DWORD info = multiByteRead(io, handle);
break;
}
// Type 11: read a sequence of parameter/value pairs.
case 0x60:
{
BYTE sizeParamIdent = (b & 0x70) >> 4; // Size of Parameter Identifier (in bytes)
BYTE sizeParamValue = (b & 0x0F); // Size of Parameter Value (in bytes)
BYTE *Ident = (BYTE*)malloc(sizeParamIdent * sizeof(BYTE));
BYTE *Value = (BYTE*)malloc(sizeParamValue * sizeof(BYTE));
io->read_proc(Ident, sizeParamIdent, 1, handle);
io->read_proc(Value, sizeParamValue, 1, handle);
free(Ident);
free(Value);
break;
}
// reserved for future use
case 0x20: // Type 01
case 0x40: // Type 10
break;
}
}
// ==========================================================
// Plugin Interface
// ==========================================================
static int s_format_id;
// ==========================================================
// Plugin Implementation
// ==========================================================
static const char * DLL_CALLCONV
Format() {
return "WBMP";
}
static const char * DLL_CALLCONV
Description() {
return "Wireless Bitmap";
}
static const char * DLL_CALLCONV
Extension() {
return "wap,wbmp,wbm";
}
static const char * DLL_CALLCONV
RegExpr() {
return NULL;
}
static const char * DLL_CALLCONV
MimeType() {
return "image/vnd.wap.wbmp";
}
static BOOL DLL_CALLCONV
SupportsExportDepth(int depth) {
return (
(depth == 1)
);
}
static BOOL DLL_CALLCONV
SupportsExportType(FREE_IMAGE_TYPE type) {
return (type == FIT_BITMAP) ? TRUE : FALSE;
}
// ----------------------------------------------------------
static FIBITMAP * DLL_CALLCONV
Load(FreeImageIO *io, fi_handle handle, int page, int flags, void *data) {
WORD x, y, width, height;
FIBITMAP *dib;
BYTE *bits; // pointer to dib data
RGBQUAD *pal; // pointer to dib palette
WBMPHEADER header;
if (handle) {
try {
// Read header information
// -----------------------
// Type
header.TypeField = (WORD)multiByteRead(io, handle);
if (header.TypeField != 0) {
throw FI_MSG_ERROR_UNSUPPORTED_FORMAT;
}
// FixHeaderField
io->read_proc(&header.FixHeaderField, 1, 1, handle);
// ExtHeaderFields
// 1 = more will follow, 0 = last octet
if (header.FixHeaderField & 0x80) {
header.ExtHeaderFields = 0x80;
while(header.ExtHeaderFields & 0x80) {
io->read_proc(&header.ExtHeaderFields, 1, 1, handle);
readExtHeader(io, handle, header.ExtHeaderFields);
}
}
// width & height
width = (WORD)multiByteRead(io, handle);
height = (WORD)multiByteRead(io, handle);
// Allocate a new dib
dib = FreeImage_Allocate(width, height, 1);
if (!dib) {
throw FI_MSG_ERROR_DIB_MEMORY;
}
// write the palette data
pal = FreeImage_GetPalette(dib);
pal[0].rgbRed = pal[0].rgbGreen = pal[0].rgbBlue = 0;
pal[1].rgbRed = pal[1].rgbGreen = pal[1].rgbBlue = 255;
// read the bitmap data
int line = FreeImage_GetLine(dib);
for (y = 0; y < height; y++) {
bits = FreeImage_GetScanLine(dib, height - 1 - y);
for (x = 0; x < line; x++) {
io->read_proc(&bits[x], 1, 1, handle);
}
}
return dib;
} catch(const char *text) {
FreeImage_OutputMessageProc(s_format_id, text);
return NULL;
}
}
return NULL;
}
static BOOL DLL_CALLCONV
Save(FreeImageIO *io, FIBITMAP *dib, fi_handle handle, int page, int flags, void *data) {
BYTE *bits; // pointer to dib data
if ((dib) && (handle)) {
try {
if (FreeImage_GetBPP(dib) != 1)
throw "Only 1-bit depth bitmaps can be saved as WBMP";
// write the header
WBMPHEADER header;
header.TypeField = 0; // Type 0: B/W, no compression
header.FixHeaderField = 0; // No ExtHeaderField
header.Width = (WORD)FreeImage_GetWidth(dib); // Image width
header.Height = (WORD)FreeImage_GetHeight(dib); // Image height
multiByteWrite(io, handle, header.TypeField);
io->write_proc(&header.FixHeaderField, 1, 1, handle);
multiByteWrite(io, handle, header.Width);
multiByteWrite(io, handle, header.Height);
// write the bitmap data
WORD linelength = (WORD)FreeImage_GetLine(dib);
for (WORD y = 0; y < header.Height; y++) {
bits = FreeImage_GetScanLine(dib, header.Height - 1 - y);
io->write_proc(&bits[0], linelength, 1, handle);
}
return TRUE;
} catch (const char* text) {
FreeImage_OutputMessageProc(s_format_id, text);
}
}
return FALSE;
}
// ==========================================================
// Init
// ==========================================================
void DLL_CALLCONV
InitWBMP(Plugin *plugin, int format_id) {
s_format_id = format_id;
plugin->format_proc = Format;
plugin->description_proc = Description;
plugin->extension_proc = Extension;
plugin->regexpr_proc = RegExpr;
plugin->open_proc = NULL;
plugin->close_proc = NULL;
plugin->pagecount_proc = NULL;
plugin->pagecapability_proc = NULL;
plugin->load_proc = Load;
plugin->save_proc = Save;
plugin->validate_proc = NULL;
plugin->mime_proc = MimeType;
plugin->supports_export_bpp_proc = SupportsExportDepth;
plugin->supports_export_type_proc = SupportsExportType;
plugin->supports_icc_profiles_proc = NULL;
}