summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorArvinder Bhathal <arvinder.bhathal@gmail.com>2017-06-21 00:29:42 -0400
committerArvinder Bhathal <arvinder.bhathal@gmail.com>2017-06-21 00:29:42 -0400
commit291c90597f7500201f8ce6778011d939d61846f8 (patch)
tree44d2cd4c2225adb799fc6d2e507a3c6a8194fd83
parent390048fa468dfee06f722da6b8ca1b79022480d6 (diff)
downloadfreetype2-291c90597f7500201f8ce6778011d939d61846f8.tar.gz
Initial commit - only C
-rw-r--r--glyphtest/main-2.c74
-rw-r--r--glyphtest/main.c74
-rwxr-xr-xglyphtest/qdbmp.c798
-rwxr-xr-xglyphtest/qdbmp.h133
4 files changed, 1079 insertions, 0 deletions
diff --git a/glyphtest/main-2.c b/glyphtest/main-2.c
new file mode 100644
index 000000000..0c8469273
--- /dev/null
+++ b/glyphtest/main-2.c
@@ -0,0 +1,74 @@
+#include <stdio.h>
+#include <ft2build.h>
+#include FT_FREETYPE_H
+#include "qdbmp.h"
+
+int main()
+{
+ // ft
+ FT_Library library;
+ FT_Face face;
+ FT_Bitmap bmp;
+ FT_UInt x, y, glyph_index;
+ FT_Byte byte;
+ BMP* qdbmp;
+ char filename[20];
+
+ if (FT_Init_FreeType(&library))
+ {
+ printf("Error: Library initialization\n");
+ }
+
+ if (FT_New_Face(library, "/usr/share/fonts/truetype/liberation/LiberationSerif-Regular.ttf", 0, &face))
+ {
+ printf("Error: Loading face\n");
+ }
+
+ // if (FT_Set_Char_Size(face, 0, 16*64, 96, 0))
+ // {
+ // printf("Error: Setting character size\n");
+ // }
+
+ if (FT_Set_Pixel_Sizes(face, 0, 48))
+ {
+ printf("Error: Setting character size\n");
+ }
+
+ for (glyph_index = 65; glyph_index < 91; glyph_index++)
+ {
+ if (FT_Load_Char(face, glyph_index, FT_LOAD_RENDER))
+ {
+ printf("Error: Loading characte.r\n");
+ }
+
+ bmp = face->glyph->bitmap;
+
+ // printf("Width: %u\n", bmp.width);
+ // printf("Height: %u\n", bmp.rows);
+ // printf("Num grays: %u\n", bmp.num_grays);
+ // printf("Pitch: %d\n", bmp.pitch);
+
+ qdbmp = BMP_Create(bmp.width,bmp.rows,24);
+ BMP_CHECK_ERROR(stdout, 1);
+
+ for (y = 0; y < bmp.rows; y++)
+ {
+ for (x = 0; x < bmp.width; x++)
+ {
+ byte = bmp.buffer[bmp.pitch * y + x];
+ BMP_SetPixelRGB(qdbmp, x, y, byte, byte, byte);
+ BMP_CHECK_ERROR(stdout, 1);
+ }
+ }
+
+ sprintf(filename, "%d-2", glyph_index);
+
+ BMP_WriteFile(qdbmp, filename);
+ BMP_CHECK_ERROR(stdout, 1);
+
+ }
+
+ FT_Done_Face(face);
+ FT_Done_FreeType(library);
+ return 0;
+} \ No newline at end of file
diff --git a/glyphtest/main.c b/glyphtest/main.c
new file mode 100644
index 000000000..cc1b60d5e
--- /dev/null
+++ b/glyphtest/main.c
@@ -0,0 +1,74 @@
+#include <stdio.h>
+#include <ft2build.h>
+#include FT_FREETYPE_H
+#include "qdbmp.h"
+
+int main()
+{
+ // ft
+ FT_Library library;
+ FT_Face face;
+ FT_Bitmap bmp;
+ FT_UInt x, y, glyph_index;
+ FT_Byte byte;
+ BMP* qdbmp;
+ char filename[20];
+
+ if (FT_Init_FreeType(&library))
+ {
+ printf("Error: Library initialization\n");
+ }
+
+ if (FT_New_Face(library, "/usr/share/fonts/truetype/liberation/LiberationSerif-Regular.ttf", 0, &face))
+ {
+ printf("Error: Loading face\n");
+ }
+
+ // if (FT_Set_Char_Size(face, 0, 16*64, 96, 0))
+ // {
+ // printf("Error: Setting character size\n");
+ // }
+
+ if (FT_Set_Pixel_Sizes(face, 0, 48))
+ {
+ printf("Error: Setting character size\n");
+ }
+
+ for (glyph_index = 65; glyph_index < 91; glyph_index++)
+ {
+ if (FT_Load_Char(face, glyph_index, FT_LOAD_RENDER))
+ {
+ printf("Error: Loading characte.r\n");
+ }
+
+ bmp = face->glyph->bitmap;
+
+ // printf("Width: %u\n", bmp.width);
+ // printf("Height: %u\n", bmp.rows);
+ // printf("Num grays: %u\n", bmp.num_grays);
+ // printf("Pitch: %d\n", bmp.pitch);
+
+ qdbmp = BMP_Create(bmp.width,bmp.rows,24);
+ BMP_CHECK_ERROR(stdout, 1);
+
+ for (y = 0; y < bmp.rows; y++)
+ {
+ for (x = 0; x < bmp.width; x++)
+ {
+ byte = bmp.buffer[bmp.pitch * y + x];
+ BMP_SetPixelRGB(qdbmp, x, y, byte, byte, byte);
+ BMP_CHECK_ERROR(stdout, 1);
+ }
+ }
+
+ sprintf(filename, "%d", glyph_index);
+
+ BMP_WriteFile(qdbmp, filename);
+ BMP_CHECK_ERROR(stdout, 1);
+
+ }
+
+ FT_Done_Face(face);
+ FT_Done_FreeType(library);
+ return 0;
+} \ No newline at end of file
diff --git a/glyphtest/qdbmp.c b/glyphtest/qdbmp.c
new file mode 100755
index 000000000..fd1337277
--- /dev/null
+++ b/glyphtest/qdbmp.c
@@ -0,0 +1,798 @@
+#include "qdbmp.h"
+#include <stdlib.h>
+#include <string.h>
+
+
+/* Bitmap header */
+typedef struct _BMP_Header
+{
+ USHORT Magic; /* Magic identifier: "BM" */
+ UINT FileSize; /* Size of the BMP file in bytes */
+ USHORT Reserved1; /* Reserved */
+ USHORT Reserved2; /* Reserved */
+ UINT DataOffset; /* Offset of image data relative to the file's start */
+ UINT HeaderSize; /* Size of the header in bytes */
+ UINT Width; /* Bitmap's width */
+ UINT Height; /* Bitmap's height */
+ USHORT Planes; /* Number of color planes in the bitmap */
+ USHORT BitsPerPixel; /* Number of bits per pixel */
+ UINT CompressionType; /* Compression type */
+ UINT ImageDataSize; /* Size of uncompressed image's data */
+ UINT HPixelsPerMeter; /* Horizontal resolution (pixels per meter) */
+ UINT VPixelsPerMeter; /* Vertical resolution (pixels per meter) */
+ UINT ColorsUsed; /* Number of color indexes in the color table that are actually used by the bitmap */
+ UINT ColorsRequired; /* Number of color indexes that are required for displaying the bitmap */
+} BMP_Header;
+
+
+/* Private data structure */
+struct _BMP
+{
+ BMP_Header Header;
+ UCHAR* Palette;
+ UCHAR* Data;
+};
+
+
+/* Holds the last error code */
+static BMP_STATUS BMP_LAST_ERROR_CODE = 0;
+
+
+/* Error description strings */
+static const char* BMP_ERROR_STRING[] =
+{
+ "",
+ "General error",
+ "Could not allocate enough memory to complete the operation",
+ "File input/output error",
+ "File not found",
+ "File is not a supported BMP variant (must be uncompressed 8, 24 or 32 BPP)",
+ "File is not a valid BMP image",
+ "An argument is invalid or out of range",
+ "The requested action is not compatible with the BMP's type"
+};
+
+
+/* Size of the palette data for 8 BPP bitmaps */
+#define BMP_PALETTE_SIZE ( 256 * 4 )
+
+
+
+/*********************************** Forward declarations **********************************/
+int ReadHeader ( BMP* bmp, FILE* f );
+int WriteHeader ( BMP* bmp, FILE* f );
+
+int ReadUINT ( UINT* x, FILE* f );
+int ReadUSHORT ( USHORT *x, FILE* f );
+
+int WriteUINT ( UINT x, FILE* f );
+int WriteUSHORT ( USHORT x, FILE* f );
+
+
+
+
+
+
+/*********************************** Public methods **********************************/
+
+
+/**************************************************************
+ Creates a blank BMP image with the specified dimensions
+ and bit depth.
+**************************************************************/
+BMP* BMP_Create( UINT width, UINT height, USHORT depth )
+{
+ BMP* bmp;
+ int bytes_per_pixel = depth >> 3;
+ UINT bytes_per_row;
+
+ if ( height <= 0 || width <= 0 )
+ {
+ BMP_LAST_ERROR_CODE = BMP_INVALID_ARGUMENT;
+ return NULL;
+ }
+
+ if ( depth != 8 && depth != 24 && depth != 32 )
+ {
+ BMP_LAST_ERROR_CODE = BMP_FILE_NOT_SUPPORTED;
+ return NULL;
+ }
+
+
+ /* Allocate the bitmap data structure */
+ bmp = calloc( 1, sizeof( BMP ) );
+ if ( bmp == NULL )
+ {
+ BMP_LAST_ERROR_CODE = BMP_OUT_OF_MEMORY;
+ return NULL;
+ }
+
+
+ /* Set header' default values */
+ bmp->Header.Magic = 0x4D42;
+ bmp->Header.Reserved1 = 0;
+ bmp->Header.Reserved2 = 0;
+ bmp->Header.HeaderSize = 40;
+ bmp->Header.Planes = 1;
+ bmp->Header.CompressionType = 0;
+ bmp->Header.HPixelsPerMeter = 0;
+ bmp->Header.VPixelsPerMeter = 0;
+ bmp->Header.ColorsUsed = 0;
+ bmp->Header.ColorsRequired = 0;
+
+
+ /* Calculate the number of bytes used to store a single image row. This is always
+ rounded up to the next multiple of 4. */
+ bytes_per_row = width * bytes_per_pixel;
+ bytes_per_row += ( bytes_per_row % 4 ? 4 - bytes_per_row % 4 : 0 );
+
+
+ /* Set header's image specific values */
+ bmp->Header.Width = width;
+ bmp->Header.Height = height;
+ bmp->Header.BitsPerPixel = depth;
+ bmp->Header.ImageDataSize = bytes_per_row * height;
+ bmp->Header.FileSize = bmp->Header.ImageDataSize + 54 + ( depth == 8 ? BMP_PALETTE_SIZE : 0 );
+ bmp->Header.DataOffset = 54 + ( depth == 8 ? BMP_PALETTE_SIZE : 0 );
+
+
+ /* Allocate palette */
+ if ( bmp->Header.BitsPerPixel == 8 )
+ {
+ bmp->Palette = (UCHAR*) calloc( BMP_PALETTE_SIZE, sizeof( UCHAR ) );
+ if ( bmp->Palette == NULL )
+ {
+ BMP_LAST_ERROR_CODE = BMP_OUT_OF_MEMORY;
+ free( bmp );
+ return NULL;
+ }
+ }
+ else
+ {
+ bmp->Palette = NULL;
+ }
+
+
+ /* Allocate pixels */
+ bmp->Data = (UCHAR*) calloc( bmp->Header.ImageDataSize, sizeof( UCHAR ) );
+ if ( bmp->Data == NULL )
+ {
+ BMP_LAST_ERROR_CODE = BMP_OUT_OF_MEMORY;
+ free( bmp->Palette );
+ free( bmp );
+ return NULL;
+ }
+
+
+ BMP_LAST_ERROR_CODE = BMP_OK;
+
+ return bmp;
+}
+
+
+/**************************************************************
+ Frees all the memory used by the specified BMP image.
+**************************************************************/
+void BMP_Free( BMP* bmp )
+{
+ if ( bmp == NULL )
+ {
+ return;
+ }
+
+ if ( bmp->Palette != NULL )
+ {
+ free( bmp->Palette );
+ }
+
+ if ( bmp->Data != NULL )
+ {
+ free( bmp->Data );
+ }
+
+ free( bmp );
+
+ BMP_LAST_ERROR_CODE = BMP_OK;
+}
+
+
+/**************************************************************
+ Reads the specified BMP image file.
+**************************************************************/
+BMP* BMP_ReadFile( const char* filename )
+{
+ BMP* bmp;
+ FILE* f;
+
+ if ( filename == NULL )
+ {
+ BMP_LAST_ERROR_CODE = BMP_INVALID_ARGUMENT;
+ return NULL;
+ }
+
+
+ /* Allocate */
+ bmp = calloc( 1, sizeof( BMP ) );
+ if ( bmp == NULL )
+ {
+ BMP_LAST_ERROR_CODE = BMP_OUT_OF_MEMORY;
+ return NULL;
+ }
+
+
+ /* Open file */
+ f = fopen( filename, "rb" );
+ if ( f == NULL )
+ {
+ BMP_LAST_ERROR_CODE = BMP_FILE_NOT_FOUND;
+ free( bmp );
+ return NULL;
+ }
+
+
+ /* Read header */
+ if ( ReadHeader( bmp, f ) != BMP_OK || bmp->Header.Magic != 0x4D42 )
+ {
+ BMP_LAST_ERROR_CODE = BMP_FILE_INVALID;
+ fclose( f );
+ free( bmp );
+ return NULL;
+ }
+
+
+ /* Verify that the bitmap variant is supported */
+ if ( ( bmp->Header.BitsPerPixel != 32 && bmp->Header.BitsPerPixel != 24 && bmp->Header.BitsPerPixel != 8 )
+ || bmp->Header.CompressionType != 0 || bmp->Header.HeaderSize != 40 )
+ {
+ BMP_LAST_ERROR_CODE = BMP_FILE_NOT_SUPPORTED;
+ fclose( f );
+ free( bmp );
+ return NULL;
+ }
+
+
+ /* Allocate and read palette */
+ if ( bmp->Header.BitsPerPixel == 8 )
+ {
+ bmp->Palette = (UCHAR*) malloc( BMP_PALETTE_SIZE * sizeof( UCHAR ) );
+ if ( bmp->Palette == NULL )
+ {
+ BMP_LAST_ERROR_CODE = BMP_OUT_OF_MEMORY;
+ fclose( f );
+ free( bmp );
+ return NULL;
+ }
+
+ if ( fread( bmp->Palette, sizeof( UCHAR ), BMP_PALETTE_SIZE, f ) != BMP_PALETTE_SIZE )
+ {
+ BMP_LAST_ERROR_CODE = BMP_FILE_INVALID;
+ fclose( f );
+ free( bmp->Palette );
+ free( bmp );
+ return NULL;
+ }
+ }
+ else /* Not an indexed image */
+ {
+ bmp->Palette = NULL;
+ }
+
+
+ /* Allocate memory for image data */
+ bmp->Data = (UCHAR*) malloc( bmp->Header.ImageDataSize );
+ if ( bmp->Data == NULL )
+ {
+ BMP_LAST_ERROR_CODE = BMP_OUT_OF_MEMORY;
+ fclose( f );
+ free( bmp->Palette );
+ free( bmp );
+ return NULL;
+ }
+
+
+ /* Read image data */
+ if ( fread( bmp->Data, sizeof( UCHAR ), bmp->Header.ImageDataSize, f ) != bmp->Header.ImageDataSize )
+ {
+ BMP_LAST_ERROR_CODE = BMP_FILE_INVALID;
+ fclose( f );
+ free( bmp->Data );
+ free( bmp->Palette );
+ free( bmp );
+ return NULL;
+ }
+
+
+ fclose( f );
+
+ BMP_LAST_ERROR_CODE = BMP_OK;
+
+ return bmp;
+}
+
+
+/**************************************************************
+ Writes the BMP image to the specified file.
+**************************************************************/
+void BMP_WriteFile( BMP* bmp, const char* filename )
+{
+ FILE* f;
+
+ if ( filename == NULL )
+ {
+ BMP_LAST_ERROR_CODE = BMP_INVALID_ARGUMENT;
+ return;
+ }
+
+
+ /* Open file */
+ f = fopen( filename, "wb" );
+ if ( f == NULL )
+ {
+ BMP_LAST_ERROR_CODE = BMP_FILE_NOT_FOUND;
+ return;
+ }
+
+
+ /* Write header */
+ if ( WriteHeader( bmp, f ) != BMP_OK )
+ {
+ BMP_LAST_ERROR_CODE = BMP_IO_ERROR;
+ fclose( f );
+ return;
+ }
+
+
+ /* Write palette */
+ if ( bmp->Palette )
+ {
+ if ( fwrite( bmp->Palette, sizeof( UCHAR ), BMP_PALETTE_SIZE, f ) != BMP_PALETTE_SIZE )
+ {
+ BMP_LAST_ERROR_CODE = BMP_IO_ERROR;
+ fclose( f );
+ return;
+ }
+ }
+
+
+ /* Write data */
+ if ( fwrite( bmp->Data, sizeof( UCHAR ), bmp->Header.ImageDataSize, f ) != bmp->Header.ImageDataSize )
+ {
+ BMP_LAST_ERROR_CODE = BMP_IO_ERROR;
+ fclose( f );
+ return;
+ }
+
+
+ BMP_LAST_ERROR_CODE = BMP_OK;
+ fclose( f );
+}
+
+
+/**************************************************************
+ Returns the image's width.
+**************************************************************/
+UINT BMP_GetWidth( BMP* bmp )
+{
+ if ( bmp == NULL )
+ {
+ BMP_LAST_ERROR_CODE = BMP_INVALID_ARGUMENT;
+ return -1;
+ }
+
+ BMP_LAST_ERROR_CODE = BMP_OK;
+
+ return ( bmp->Header.Width );
+}
+
+
+/**************************************************************
+ Returns the image's height.
+**************************************************************/
+UINT BMP_GetHeight( BMP* bmp )
+{
+ if ( bmp == NULL )
+ {
+ BMP_LAST_ERROR_CODE = BMP_INVALID_ARGUMENT;
+ return -1;
+ }
+
+ BMP_LAST_ERROR_CODE = BMP_OK;
+
+ return ( bmp->Header.Height );
+}
+
+
+/**************************************************************
+ Returns the image's color depth (bits per pixel).
+**************************************************************/
+USHORT BMP_GetDepth( BMP* bmp )
+{
+ if ( bmp == NULL )
+ {
+ BMP_LAST_ERROR_CODE = BMP_INVALID_ARGUMENT;
+ return -1;
+ }
+
+ BMP_LAST_ERROR_CODE = BMP_OK;
+
+ return ( bmp->Header.BitsPerPixel );
+}
+
+
+/**************************************************************
+ Populates the arguments with the specified pixel's RGB
+ values.
+**************************************************************/
+void BMP_GetPixelRGB( BMP* bmp, UINT x, UINT y, UCHAR* r, UCHAR* g, UCHAR* b )
+{
+ UCHAR* pixel;
+ UINT bytes_per_row;
+ UCHAR bytes_per_pixel;
+
+ if ( bmp == NULL || x < 0 || x >= bmp->Header.Width || y < 0 || y >= bmp->Header.Height )
+ {
+ BMP_LAST_ERROR_CODE = BMP_INVALID_ARGUMENT;
+ }
+ else
+ {
+ BMP_LAST_ERROR_CODE = BMP_OK;
+
+ bytes_per_pixel = bmp->Header.BitsPerPixel >> 3;
+
+ /* Row's size is rounded up to the next multiple of 4 bytes */
+ bytes_per_row = bmp->Header.ImageDataSize / bmp->Header.Height;
+
+ /* Calculate the location of the relevant pixel (rows are flipped) */
+ pixel = bmp->Data + ( ( bmp->Header.Height - y - 1 ) * bytes_per_row + x * bytes_per_pixel );
+
+
+ /* In indexed color mode the pixel's value is an index within the palette */
+ if ( bmp->Header.BitsPerPixel == 8 )
+ {
+ pixel = bmp->Palette + *pixel * 4;
+ }
+
+ /* Note: colors are stored in BGR order */
+ if ( r ) *r = *( pixel + 2 );
+ if ( g ) *g = *( pixel + 1 );
+ if ( b ) *b = *( pixel + 0 );
+ }
+}
+
+
+/**************************************************************
+ Sets the specified pixel's RGB values.
+**************************************************************/
+void BMP_SetPixelRGB( BMP* bmp, UINT x, UINT y, UCHAR r, UCHAR g, UCHAR b )
+{
+ UCHAR* pixel;
+ UINT bytes_per_row;
+ UCHAR bytes_per_pixel;
+
+ if ( bmp == NULL || x < 0 || x >= bmp->Header.Width || y < 0 || y >= bmp->Header.Height )
+ {
+ BMP_LAST_ERROR_CODE = BMP_INVALID_ARGUMENT;
+ }
+
+ else if ( bmp->Header.BitsPerPixel != 24 && bmp->Header.BitsPerPixel != 32 )
+ {
+ BMP_LAST_ERROR_CODE = BMP_TYPE_MISMATCH;
+ }
+
+ else
+ {
+ BMP_LAST_ERROR_CODE = BMP_OK;
+
+ bytes_per_pixel = bmp->Header.BitsPerPixel >> 3;
+
+ /* Row's size is rounded up to the next multiple of 4 bytes */
+ bytes_per_row = bmp->Header.ImageDataSize / bmp->Header.Height;
+
+ /* Calculate the location of the relevant pixel (rows are flipped) */
+ pixel = bmp->Data + ( ( bmp->Header.Height - y - 1 ) * bytes_per_row + x * bytes_per_pixel );
+
+ /* Note: colors are stored in BGR order */
+ *( pixel + 2 ) = r;
+ *( pixel + 1 ) = g;
+ *( pixel + 0 ) = b;
+ }
+}
+
+
+/**************************************************************
+ Gets the specified pixel's color index.
+**************************************************************/
+void BMP_GetPixelIndex( BMP* bmp, UINT x, UINT y, UCHAR* val )
+{
+ UCHAR* pixel;
+ UINT bytes_per_row;
+
+ if ( bmp == NULL || x < 0 || x >= bmp->Header.Width || y < 0 || y >= bmp->Header.Height )
+ {
+ BMP_LAST_ERROR_CODE = BMP_INVALID_ARGUMENT;
+ }
+
+ else if ( bmp->Header.BitsPerPixel != 8 )
+ {
+ BMP_LAST_ERROR_CODE = BMP_TYPE_MISMATCH;
+ }
+
+ else
+ {
+ BMP_LAST_ERROR_CODE = BMP_OK;
+
+ /* Row's size is rounded up to the next multiple of 4 bytes */
+ bytes_per_row = bmp->Header.ImageDataSize / bmp->Header.Height;
+
+ /* Calculate the location of the relevant pixel */
+ pixel = bmp->Data + ( ( bmp->Header.Height - y - 1 ) * bytes_per_row + x );
+
+
+ if ( val ) *val = *pixel;
+ }
+}
+
+
+/**************************************************************
+ Sets the specified pixel's color index.
+**************************************************************/
+void BMP_SetPixelIndex( BMP* bmp, UINT x, UINT y, UCHAR val )
+{
+ UCHAR* pixel;
+ UINT bytes_per_row;
+
+ if ( bmp == NULL || x < 0 || x >= bmp->Header.Width || y < 0 || y >= bmp->Header.Height )
+ {
+ BMP_LAST_ERROR_CODE = BMP_INVALID_ARGUMENT;
+ }
+
+ else if ( bmp->Header.BitsPerPixel != 8 )
+ {
+ BMP_LAST_ERROR_CODE = BMP_TYPE_MISMATCH;
+ }
+
+ else
+ {
+ BMP_LAST_ERROR_CODE = BMP_OK;
+
+ /* Row's size is rounded up to the next multiple of 4 bytes */
+ bytes_per_row = bmp->Header.ImageDataSize / bmp->Header.Height;
+
+ /* Calculate the location of the relevant pixel */
+ pixel = bmp->Data + ( ( bmp->Header.Height - y - 1 ) * bytes_per_row + x );
+
+ *pixel = val;
+ }
+}
+
+
+/**************************************************************
+ Gets the color value for the specified palette index.
+**************************************************************/
+void BMP_GetPaletteColor( BMP* bmp, UCHAR index, UCHAR* r, UCHAR* g, UCHAR* b )
+{
+ if ( bmp == NULL )
+ {
+ BMP_LAST_ERROR_CODE = BMP_INVALID_ARGUMENT;
+ }
+
+ else if ( bmp->Header.BitsPerPixel != 8 )
+ {
+ BMP_LAST_ERROR_CODE = BMP_TYPE_MISMATCH;
+ }
+
+ else
+ {
+ if ( r ) *r = *( bmp->Palette + index * 4 + 2 );
+ if ( g ) *g = *( bmp->Palette + index * 4 + 1 );
+ if ( b ) *b = *( bmp->Palette + index * 4 + 0 );
+
+ BMP_LAST_ERROR_CODE = BMP_OK;
+ }
+}
+
+
+/**************************************************************
+ Sets the color value for the specified palette index.
+**************************************************************/
+void BMP_SetPaletteColor( BMP* bmp, UCHAR index, UCHAR r, UCHAR g, UCHAR b )
+{
+ if ( bmp == NULL )
+ {
+ BMP_LAST_ERROR_CODE = BMP_INVALID_ARGUMENT;
+ }
+
+ else if ( bmp->Header.BitsPerPixel != 8 )
+ {
+ BMP_LAST_ERROR_CODE = BMP_TYPE_MISMATCH;
+ }
+
+ else
+ {
+ *( bmp->Palette + index * 4 + 2 ) = r;
+ *( bmp->Palette + index * 4 + 1 ) = g;
+ *( bmp->Palette + index * 4 + 0 ) = b;
+
+ BMP_LAST_ERROR_CODE = BMP_OK;
+ }
+}
+
+
+/**************************************************************
+ Returns the last error code.
+**************************************************************/
+BMP_STATUS BMP_GetError()
+{
+ return BMP_LAST_ERROR_CODE;
+}
+
+
+/**************************************************************
+ Returns a description of the last error code.
+**************************************************************/
+const char* BMP_GetErrorDescription()
+{
+ if ( BMP_LAST_ERROR_CODE > 0 && BMP_LAST_ERROR_CODE < BMP_ERROR_NUM )
+ {
+ return BMP_ERROR_STRING[ BMP_LAST_ERROR_CODE ];
+ }
+ else
+ {
+ return NULL;
+ }
+}
+
+
+
+
+
+/*********************************** Private methods **********************************/
+
+
+/**************************************************************
+ Reads the BMP file's header into the data structure.
+ Returns BMP_OK on success.
+**************************************************************/
+int ReadHeader( BMP* bmp, FILE* f )
+{
+ if ( bmp == NULL || f == NULL )
+ {
+ return BMP_INVALID_ARGUMENT;
+ }
+
+ /* The header's fields are read one by one, and converted from the format's
+ little endian to the system's native representation. */
+ if ( !ReadUSHORT( &( bmp->Header.Magic ), f ) ) return BMP_IO_ERROR;
+ if ( !ReadUINT( &( bmp->Header.FileSize ), f ) ) return BMP_IO_ERROR;
+ if ( !ReadUSHORT( &( bmp->Header.Reserved1 ), f ) ) return BMP_IO_ERROR;
+ if ( !ReadUSHORT( &( bmp->Header.Reserved2 ), f ) ) return BMP_IO_ERROR;
+ if ( !ReadUINT( &( bmp->Header.DataOffset ), f ) ) return BMP_IO_ERROR;
+ if ( !ReadUINT( &( bmp->Header.HeaderSize ), f ) ) return BMP_IO_ERROR;
+ if ( !ReadUINT( &( bmp->Header.Width ), f ) ) return BMP_IO_ERROR;
+ if ( !ReadUINT( &( bmp->Header.Height ), f ) ) return BMP_IO_ERROR;
+ if ( !ReadUSHORT( &( bmp->Header.Planes ), f ) ) return BMP_IO_ERROR;
+ if ( !ReadUSHORT( &( bmp->Header.BitsPerPixel ), f ) ) return BMP_IO_ERROR;
+ if ( !ReadUINT( &( bmp->Header.CompressionType ), f ) ) return BMP_IO_ERROR;
+ if ( !ReadUINT( &( bmp->Header.ImageDataSize ), f ) ) return BMP_IO_ERROR;
+ if ( !ReadUINT( &( bmp->Header.HPixelsPerMeter ), f ) ) return BMP_IO_ERROR;
+ if ( !ReadUINT( &( bmp->Header.VPixelsPerMeter ), f ) ) return BMP_IO_ERROR;
+ if ( !ReadUINT( &( bmp->Header.ColorsUsed ), f ) ) return BMP_IO_ERROR;
+ if ( !ReadUINT( &( bmp->Header.ColorsRequired ), f ) ) return BMP_IO_ERROR;
+
+ return BMP_OK;
+}
+
+
+/**************************************************************
+ Writes the BMP file's header into the data structure.
+ Returns BMP_OK on success.
+**************************************************************/
+int WriteHeader( BMP* bmp, FILE* f )
+{
+ if ( bmp == NULL || f == NULL )
+ {
+ return BMP_INVALID_ARGUMENT;
+ }
+
+ /* The header's fields are written one by one, and converted to the format's
+ little endian representation. */
+ if ( !WriteUSHORT( bmp->Header.Magic, f ) ) return BMP_IO_ERROR;
+ if ( !WriteUINT( bmp->Header.FileSize, f ) ) return BMP_IO_ERROR;
+ if ( !WriteUSHORT( bmp->Header.Reserved1, f ) ) return BMP_IO_ERROR;
+ if ( !WriteUSHORT( bmp->Header.Reserved2, f ) ) return BMP_IO_ERROR;
+ if ( !WriteUINT( bmp->Header.DataOffset, f ) ) return BMP_IO_ERROR;
+ if ( !WriteUINT( bmp->Header.HeaderSize, f ) ) return BMP_IO_ERROR;
+ if ( !WriteUINT( bmp->Header.Width, f ) ) return BMP_IO_ERROR;
+ if ( !WriteUINT( bmp->Header.Height, f ) ) return BMP_IO_ERROR;
+ if ( !WriteUSHORT( bmp->Header.Planes, f ) ) return BMP_IO_ERROR;
+ if ( !WriteUSHORT( bmp->Header.BitsPerPixel, f ) ) return BMP_IO_ERROR;
+ if ( !WriteUINT( bmp->Header.CompressionType, f ) ) return BMP_IO_ERROR;
+ if ( !WriteUINT( bmp->Header.ImageDataSize, f ) ) return BMP_IO_ERROR;
+ if ( !WriteUINT( bmp->Header.HPixelsPerMeter, f ) ) return BMP_IO_ERROR;
+ if ( !WriteUINT( bmp->Header.VPixelsPerMeter, f ) ) return BMP_IO_ERROR;
+ if ( !WriteUINT( bmp->Header.ColorsUsed, f ) ) return BMP_IO_ERROR;
+ if ( !WriteUINT( bmp->Header.ColorsRequired, f ) ) return BMP_IO_ERROR;
+
+ return BMP_OK;
+}
+
+
+/**************************************************************
+ Reads a little-endian unsigned int from the file.
+ Returns non-zero on success.
+**************************************************************/
+int ReadUINT( UINT* x, FILE* f )
+{
+ UCHAR little[ 4 ]; /* BMPs use 32 bit ints */
+
+ if ( x == NULL || f == NULL )
+ {
+ return 0;
+ }
+
+ if ( fread( little, 4, 1, f ) != 1 )
+ {
+ return 0;
+ }
+
+ *x = ( little[ 3 ] << 24 | little[ 2 ] << 16 | little[ 1 ] << 8 | little[ 0 ] );
+
+ return 1;
+}
+
+
+/**************************************************************
+ Reads a little-endian unsigned short int from the file.
+ Returns non-zero on success.
+**************************************************************/
+int ReadUSHORT( USHORT *x, FILE* f )
+{
+ UCHAR little[ 2 ]; /* BMPs use 16 bit shorts */
+
+ if ( x == NULL || f == NULL )
+ {
+ return 0;
+ }
+
+ if ( fread( little, 2, 1, f ) != 1 )
+ {
+ return 0;
+ }
+
+ *x = ( little[ 1 ] << 8 | little[ 0 ] );
+
+ return 1;
+}
+
+
+/**************************************************************
+ Writes a little-endian unsigned int to the file.
+ Returns non-zero on success.
+**************************************************************/
+int WriteUINT( UINT x, FILE* f )
+{
+ UCHAR little[ 4 ]; /* BMPs use 32 bit ints */
+
+ little[ 3 ] = (UCHAR)( ( x & 0xff000000 ) >> 24 );
+ little[ 2 ] = (UCHAR)( ( x & 0x00ff0000 ) >> 16 );
+ little[ 1 ] = (UCHAR)( ( x & 0x0000ff00 ) >> 8 );
+ little[ 0 ] = (UCHAR)( ( x & 0x000000ff ) >> 0 );
+
+ return ( f && fwrite( little, 4, 1, f ) == 1 );
+}
+
+
+/**************************************************************
+ Writes a little-endian unsigned short int to the file.
+ Returns non-zero on success.
+**************************************************************/
+int WriteUSHORT( USHORT x, FILE* f )
+{
+ UCHAR little[ 2 ]; /* BMPs use 16 bit shorts */
+
+ little[ 1 ] = (UCHAR)( ( x & 0xff00 ) >> 8 );
+ little[ 0 ] = (UCHAR)( ( x & 0x00ff ) >> 0 );
+
+ return ( f && fwrite( little, 2, 1, f ) == 1 );
+}
+
diff --git a/glyphtest/qdbmp.h b/glyphtest/qdbmp.h
new file mode 100755
index 000000000..d6c0e6c45
--- /dev/null
+++ b/glyphtest/qdbmp.h
@@ -0,0 +1,133 @@
+#ifndef _BMP_H_
+#define _BMP_H_
+
+
+/**************************************************************
+
+ QDBMP - Quick n' Dirty BMP
+
+ v1.0.0 - 2007-04-07
+ http://qdbmp.sourceforge.net
+
+
+ The library supports the following BMP variants:
+ 1. Uncompressed 32 BPP (alpha values are ignored)
+ 2. Uncompressed 24 BPP
+ 3. Uncompressed 8 BPP (indexed color)
+
+ QDBMP is free and open source software, distributed
+ under the MIT licence.
+
+ Copyright (c) 2007 Chai Braudo (braudo@users.sourceforge.net)
+
+ Permission is hereby granted, free of charge, to any person obtaining a copy
+ of this software and associated documentation files (the "Software"), to deal
+ in the Software without restriction, including without limitation the rights
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ copies of the Software, and to permit persons to whom the Software is
+ furnished to do so, subject to the following conditions:
+
+ The above copyright notice and this permission notice shall be included in
+ all copies or substantial portions of the Software.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ THE SOFTWARE.
+
+**************************************************************/
+
+#include <stdio.h>
+
+
+
+/* Type definitions */
+#ifndef UINT
+ #define UINT unsigned long int
+#endif
+
+#ifndef USHORT
+ #define USHORT unsigned short
+#endif
+
+#ifndef UCHAR
+ #define UCHAR unsigned char
+#endif
+
+
+/* Version */
+#define QDBMP_VERSION_MAJOR 1
+#define QDBMP_VERSION_MINOR 0
+#define QDBMP_VERSION_PATCH 1
+
+
+/* Error codes */
+typedef enum
+{
+ BMP_OK = 0, /* No error */
+ BMP_ERROR, /* General error */
+ BMP_OUT_OF_MEMORY, /* Could not allocate enough memory to complete the operation */
+ BMP_IO_ERROR, /* General input/output error */
+ BMP_FILE_NOT_FOUND, /* File not found */
+ BMP_FILE_NOT_SUPPORTED, /* File is not a supported BMP variant */
+ BMP_FILE_INVALID, /* File is not a BMP image or is an invalid BMP */
+ BMP_INVALID_ARGUMENT, /* An argument is invalid or out of range */
+ BMP_TYPE_MISMATCH, /* The requested action is not compatible with the BMP's type */
+ BMP_ERROR_NUM
+} BMP_STATUS;
+
+
+/* Bitmap image */
+typedef struct _BMP BMP;
+
+
+
+
+/*********************************** Public methods **********************************/
+
+
+/* Construction/destruction */
+BMP* BMP_Create ( UINT width, UINT height, USHORT depth );
+void BMP_Free ( BMP* bmp );
+
+
+/* I/O */
+BMP* BMP_ReadFile ( const char* filename );
+void BMP_WriteFile ( BMP* bmp, const char* filename );
+
+
+/* Meta info */
+UINT BMP_GetWidth ( BMP* bmp );
+UINT BMP_GetHeight ( BMP* bmp );
+USHORT BMP_GetDepth ( BMP* bmp );
+
+
+/* Pixel access */
+void BMP_GetPixelRGB ( BMP* bmp, UINT x, UINT y, UCHAR* r, UCHAR* g, UCHAR* b );
+void BMP_SetPixelRGB ( BMP* bmp, UINT x, UINT y, UCHAR r, UCHAR g, UCHAR b );
+void BMP_GetPixelIndex ( BMP* bmp, UINT x, UINT y, UCHAR* val );
+void BMP_SetPixelIndex ( BMP* bmp, UINT x, UINT y, UCHAR val );
+
+
+/* Palette handling */
+void BMP_GetPaletteColor ( BMP* bmp, UCHAR index, UCHAR* r, UCHAR* g, UCHAR* b );
+void BMP_SetPaletteColor ( BMP* bmp, UCHAR index, UCHAR r, UCHAR g, UCHAR b );
+
+
+/* Error handling */
+BMP_STATUS BMP_GetError ();
+const char* BMP_GetErrorDescription ();
+
+
+/* Useful macro that may be used after each BMP operation to check for an error */
+#define BMP_CHECK_ERROR( output_file, return_value ) \
+ if ( BMP_GetError() != BMP_OK ) \
+ { \
+ fprintf( ( output_file ), "BMP error: %s\n", BMP_GetErrorDescription() ); \
+ return( return_value ); \
+ } \
+
+#endif