00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035
00036
00037
00038
00039
00040
00041
00042
00043
00044
00045
00046
00047 #include "BitmapFont.h"
00048
00049 #include "Image/ByteImage.h"
00050 #include "Image/PrimitivesDrawer.h"
00051
00052 #include <stdio.h>
00053 #include <string.h>
00054
00055
00056
00057
00058
00059
00060 #define PCF_PROPERTIES (1<<0)
00061 #define PCF_ACCELERATORS (1<<1)
00062 #define PCF_METRICS (1<<2)
00063 #define PCF_BITMAPS (1<<3)
00064 #define PCF_INK_METRICS (1<<4)
00065 #define PCF_BDF_ENCODINGS (1<<5)
00066 #define PCF_SWIDTHS (1<<6)
00067 #define PCF_GLYPH_NAMES (1<<7)
00068 #define PCF_BDF_ACCELERATORS (1<<8)
00069
00070 #define PCF_DEFAULT_FORMAT 0x00000000
00071 #define PCF_INKBOUNDS 0x00000200
00072 #define PCF_ACCEL_W_INKBOUNDS 0x00000100
00073 #define PCF_COMPRESSED_METRICS 0x00000100
00074
00075 #define PCF_GLYPH_PAD_MASK (3<<0)
00076 #define PCF_BYTE_MASK (1<<2)
00077 #define PCF_BIT_MASK (1<<3)
00078 #define PCF_SCAN_UNIT_MASK (3<<4)
00079
00080
00081
00082
00083
00084
00085 struct TOCEntry
00086 {
00087 int type;
00088 int format;
00089 int size;
00090 int offset;
00091 };
00092
00093 struct PCFMetricsTable
00094 {
00095 int format;
00096 short metrics_count;
00097 };
00098
00099 struct PCFEncodingTable
00100 {
00101 int format;
00102 short min_char_or_byte2;
00103 short max_char_or_byte2;
00104 short min_byte1;
00105 short max_byte1;
00106 short default_char;
00107 };
00108
00109 struct PCFAcceleratorTable
00110 {
00111 int format;
00112 unsigned char noOverlap;
00113 unsigned char constantMetrics;
00114 unsigned char terminalFont;
00115 unsigned char constantWidth;
00116 unsigned char inkInside;
00117 unsigned char inkMetrics;
00118 unsigned char drawDirection;
00119 unsigned char padding;
00120 int fontAscent;
00121 int fontDescent;
00122 int maxOverlap;
00123 };
00124
00125 struct PCFMetricsEntry
00126 {
00127 int left_sided_bearing;
00128 int right_side_bearing;
00129 int character_width;
00130 int character_ascent;
00131 int character_descent;
00132 int character_attributes;
00133 };
00134
00135
00136 struct BitmapCharacter
00137 {
00138 int *pCoordinatesX;
00139 int *pCoordinatesY;
00140 int nCoordinates;
00141 int nWidth;
00142 int nAscent;
00143 int nDescent;
00144 };
00145
00146
00147
00148
00149
00150
00151
00152 CBitmapFont::CBitmapFont()
00153 {
00154 m_pCharacters = 0;
00155 m_pEncodingTable = 0;
00156
00157 Reset();
00158 }
00159
00160 CBitmapFont::~CBitmapFont()
00161 {
00162 Reset();
00163 }
00164
00165 void CBitmapFont::Reset()
00166 {
00167 if (m_pCharacters)
00168 {
00169 for (int i = 0; i < m_nCharacters; i++)
00170 {
00171 if (m_pCharacters[i].pCoordinatesX)
00172 {
00173 delete [] m_pCharacters[i].pCoordinatesX;
00174 delete [] m_pCharacters[i].pCoordinatesY;
00175 }
00176 }
00177
00178 delete [] m_pCharacters;
00179 m_pCharacters = 0;
00180 }
00181
00182 delete [] m_pEncodingTable;
00183 m_pEncodingTable = 0;
00184
00185 m_nCharacters = 0;
00186 m_nMaxEncoding = 0;
00187 m_nFontHeight = 0;
00188 }
00189
00190 void CBitmapFont::Init(int nCharacters)
00191 {
00192 Reset();
00193
00194 m_nCharacters = nCharacters;
00195
00196 m_pCharacters = new BitmapCharacter[m_nCharacters];
00197
00198 int i;
00199
00200 for (int i = 0; i < m_nCharacters; i++)
00201 {
00202 m_pCharacters[i].pCoordinatesX = 0;
00203 m_pCharacters[i].pCoordinatesY = 0;
00204 m_pCharacters[i].nCoordinates = 0;
00205 m_pCharacters[i].nWidth = 0;
00206 }
00207
00208 m_nMaxEncoding = 256;
00209 m_pEncodingTable = new int[m_nMaxEncoding];
00210
00211 for (i = 0; i < m_nMaxEncoding; i++)
00212 m_pEncodingTable[i] = -1;
00213 }
00214
00215 bool CBitmapFont::GetCharacterInformation(unsigned char encoding, int *&pCoordinatesX, int *&pCoordinatesY, int &nCoordinates, int &nWidth) const
00216 {
00217 const int nIndex = m_pEncodingTable[encoding];
00218
00219 if (nIndex == -1)
00220 return false;
00221
00222 pCoordinatesX = m_pCharacters[nIndex].pCoordinatesX;
00223 pCoordinatesY = m_pCharacters[nIndex].pCoordinatesY;
00224 nCoordinates = m_pCharacters[nIndex].nCoordinates;
00225 nWidth = m_pCharacters[nIndex].nWidth;
00226
00227 return true;
00228 }
00229
00230 void CBitmapFont::SetGlyph(int nIndex, int *pCoordinatesX, int *pCoordinatesY, int nCoordinates, int nWidth, int nAscent, int nDescent)
00231 {
00232 if (m_pCharacters[nIndex].pCoordinatesY)
00233 {
00234 delete [] m_pCharacters[nIndex].pCoordinatesY;
00235 delete [] m_pCharacters[nIndex].pCoordinatesY;
00236 }
00237
00238 m_pCharacters[nIndex].pCoordinatesX = new int[nCoordinates];
00239 m_pCharacters[nIndex].pCoordinatesY = new int[nCoordinates];
00240 m_pCharacters[nIndex].nCoordinates = nCoordinates;
00241 m_pCharacters[nIndex].nWidth = nWidth;
00242
00243
00244 for (int i = 0; i < nCoordinates; i++)
00245 {
00246 m_pCharacters[nIndex].pCoordinatesX[i] = pCoordinatesX[i];
00247 m_pCharacters[nIndex].pCoordinatesY[i] = pCoordinatesY[i];
00248 }
00249 }
00250
00251 void CBitmapFont::AddEncoding(int nEncoding, int nIndex)
00252 {
00253 if (nIndex >= m_nCharacters)
00254 {
00255 printf("error: encoding %i indexed invalid glyph index %i (%i glyphs)\n", nEncoding, nIndex, m_nCharacters);
00256 return;
00257 }
00258
00259 if (nEncoding < 0 || nEncoding >= m_nMaxEncoding)
00260 {
00261 printf("error: encoding %i is not valid\n", nEncoding);
00262 return;
00263 }
00264
00265 m_pEncodingTable[nEncoding] = nIndex;
00266 }
00267
00268
00269
00270 static short my_invert_byte_order_short(short x, int bInvert = false)
00271 {
00272 if (!bInvert)
00273 return x;
00274
00275 unsigned short result = 0;
00276
00277 result |= (x & 0x00ff) << 8;
00278 result |= (x & 0xff00) >> 8;
00279
00280 return result;
00281 }
00282
00283 static unsigned int my_invert_byte_order_int(unsigned int x, int bInvert = false)
00284 {
00285 if (!bInvert)
00286 return x;
00287
00288 unsigned int result = 0;
00289
00290 result |= (x & 0x000000ff) << 24;
00291 result |= (x & 0x0000ff00) << 8;
00292 result |= (x & 0x00ff0000) >> 8;
00293 result |= (x & 0xff000000) >> 24;
00294
00295 return result;
00296 }
00297
00298
00299 bool CBitmapFont::LoadPCFFont(const char *pFilePath)
00300 {
00301 FILE *f = fopen(pFilePath, "rb");
00302 if (!f)
00303 {
00304 printf("error: could not open file for reading\n");
00305 return false;
00306 }
00307
00308 fseek(f, 0, SEEK_END);
00309 const int nFileSize = ftell(f);
00310 fseek(f, 0, SEEK_SET);
00311
00312
00313 unsigned char *pBuffer = new unsigned char[nFileSize];
00314
00315
00316 if (fread(pBuffer, nFileSize, 1, f) != 1)
00317 {
00318 printf("error: could not read file\n");
00319 delete [] pBuffer;
00320 return false;
00321 }
00322
00323
00324 if (strncmp((char *) pBuffer, "\1fcp", 4) != 0)
00325 {
00326 printf("error: file header is not a valid PCF header\n");
00327 delete [] pBuffer;
00328 return false;
00329 }
00330
00331 const int nTableCount = my_invert_byte_order_int(*((int *) (pBuffer + 4)));
00332
00333 TOCEntry *pTOCEntries = (TOCEntry *) (pBuffer + 8);
00334 TOCEntry *pBitmapTOCEntry = 0;
00335 TOCEntry *pAcceleratorTOCEntry = 0;
00336 TOCEntry *pMetricsTOCEntry = 0;
00337 TOCEntry *pEncodingTOCEntry = 0;
00338
00339 int i;
00340
00341 for (i = 0; i < nTableCount; i++)
00342 {
00343 if ((pTOCEntries[i].format & PCF_BIT_MASK) == 0)
00344 {
00345 printf("error: inverse bit order not implmeented\n");
00346 delete [] pBuffer;
00347 return false;
00348 }
00349
00350 switch (pTOCEntries[i].type)
00351 {
00352 case PCF_BITMAPS: pBitmapTOCEntry = pTOCEntries + i; break;
00353 case PCF_ACCELERATORS: pAcceleratorTOCEntry = pTOCEntries + i; break;
00354 case PCF_METRICS: pMetricsTOCEntry = pTOCEntries + i; break;
00355 case PCF_BDF_ENCODINGS: pEncodingTOCEntry = pTOCEntries + i; break;
00356 default: break;
00357 }
00358 }
00359
00360 if (!pBitmapTOCEntry || !pAcceleratorTOCEntry || !pMetricsTOCEntry || !pEncodingTOCEntry)
00361 {
00362 printf("error: PCF does not contain all tables\n");
00363 delete [] pBuffer;
00364 return false;
00365 }
00366
00367
00368 PCFAcceleratorTable *pAcceleratorTable = (PCFAcceleratorTable *) (pBuffer + pAcceleratorTOCEntry->offset);
00369
00370 pAcceleratorTable->format = my_invert_byte_order_int(pAcceleratorTable->format);
00371 pAcceleratorTable->fontAscent = my_invert_byte_order_int(pAcceleratorTable->fontAscent, pAcceleratorTable->format & PCF_BYTE_MASK);
00372 pAcceleratorTable->fontDescent = my_invert_byte_order_int(pAcceleratorTable->fontDescent, pAcceleratorTable->format & PCF_BYTE_MASK);
00373
00374
00375 PCFMetricsTable *pMetricsTable = (PCFMetricsTable *) (pBuffer + pMetricsTOCEntry->offset);
00376
00377 pMetricsTable->format = my_invert_byte_order_int(pMetricsTable->format);
00378 pMetricsTable->metrics_count = my_invert_byte_order_short(pMetricsTable->metrics_count, pMetricsTable->format & PCF_BYTE_MASK);
00379
00380
00381 PCFEncodingTable *pEncodingTable = (PCFEncodingTable *) (pBuffer + pEncodingTOCEntry->offset);
00382
00383 pEncodingTable->format = my_invert_byte_order_int(pEncodingTable->format);
00384 pEncodingTable->min_char_or_byte2 = my_invert_byte_order_short(pEncodingTable->min_char_or_byte2, pEncodingTable->format & PCF_BYTE_MASK);
00385 pEncodingTable->max_char_or_byte2 = my_invert_byte_order_short(pEncodingTable->max_char_or_byte2, pEncodingTable->format & PCF_BYTE_MASK);
00386 pEncodingTable->min_byte1 = my_invert_byte_order_short(pEncodingTable->min_byte1, pEncodingTable->format & PCF_BYTE_MASK);
00387 pEncodingTable->max_byte1 = my_invert_byte_order_short(pEncodingTable->max_byte1, pEncodingTable->format & PCF_BYTE_MASK);
00388
00389 if (pEncodingTable->min_byte1 != 0 || pEncodingTable->max_byte1 != 0)
00390 {
00391 printf("error: 2 byte encoding not implemented\n");
00392 delete [] pBuffer;
00393 return false;
00394 }
00395
00396 const short *pEncodingData = (const short *) (pBuffer + pEncodingTOCEntry->offset + 14);
00397
00398
00399 int *pBitmapTable = (int *) (pBuffer + pBitmapTOCEntry->offset);
00400
00401 const int nBitmapFormat = my_invert_byte_order_int(pBitmapTable[0]);
00402 const int nGlyphs = my_invert_byte_order_int(pBitmapTable[1], nBitmapFormat & PCF_BYTE_MASK);
00403 const int nBitmapSize = my_invert_byte_order_int(pBitmapTable[2 + nGlyphs + (nBitmapFormat & 3)], nBitmapFormat & PCF_BYTE_MASK);
00404 const int *pGlyphOffsets = pBitmapTable + 2;
00405
00406 int nBytesPerLine = 0;
00407 switch (nBitmapFormat & 3)
00408 {
00409 case 0: nBytesPerLine = 1;
00410 case 1: nBytesPerLine = 2;
00411 case 2: nBytesPerLine = 4;
00412 }
00413
00414 if (nBytesPerLine == 0)
00415 {
00416 printf("error: bitmap format invalid\n");
00417 delete [] pBuffer;
00418 return false;
00419 }
00420
00421
00422
00423
00424
00425 if (nBitmapSize % nGlyphs != 0)
00426 {
00427 printf("error: irregular glyph size\n");
00428 delete [] pBuffer;
00429 return false;
00430 }
00431
00432 const int nBytesPerGlyph = nBitmapSize / nGlyphs;
00433
00434 if (nBytesPerGlyph % nBytesPerLine != 0)
00435 {
00436 printf("error: irregular line size\n");
00437 delete [] pBuffer;
00438 return false;
00439 }
00440
00441 const int nLinesPerGlyph = nBytesPerGlyph / nBytesPerLine;
00442
00443 if (pMetricsTable->metrics_count != nGlyphs)
00444 {
00445 printf("error: glyph count does not match metrics count\n");
00446 delete [] pBuffer;
00447 return false;
00448 }
00449
00450
00451 Init(nGlyphs);
00452
00453
00454 int *pCoordinatesX = new int[nLinesPerGlyph * nBytesPerLine * 8];
00455 int *pCoordinatesY = new int[nLinesPerGlyph * nBytesPerLine * 8];
00456
00457 for (int n = 0; n < nGlyphs; n++)
00458 {
00459 const unsigned char *pGlyphBitmapData = ((const unsigned char *) (pBitmapTable + 6 + nGlyphs)) + my_invert_byte_order_int(pGlyphOffsets[n], nBitmapFormat & PCF_BYTE_MASK);
00460
00461
00462 int nCoordinates = 0;
00463
00464 for (int i = 0; i < nLinesPerGlyph; i++)
00465 {
00466 for (int j = 0; j < nBytesPerLine; j++)
00467 {
00468 const unsigned char value = pGlyphBitmapData[i * nBytesPerLine + j];
00469
00470 for (int k = 0; k < 8; k++)
00471 if ((value << k) & 128)
00472 {
00473 pCoordinatesX[nCoordinates] = j * 8 + k;
00474 pCoordinatesY[nCoordinates] = i;
00475 nCoordinates++;
00476 }
00477 }
00478 }
00479
00480
00481 int nWidth, nAscent, nDescent;
00482
00483 if (pMetricsTable->format & PCF_COMPRESSED_METRICS)
00484 {
00485 const unsigned char *pMetricsData = (unsigned char *) (pBuffer + pMetricsTOCEntry->offset + 6);
00486 nWidth = pMetricsData[n * 5 + 2] - 0x80;
00487 nAscent = pMetricsData[n * 5 + 3] - 0x80;
00488 nDescent = pMetricsData[n * 5 + 4] - 0x80;
00489 }
00490 else
00491 {
00492 const short *pMetricsData = (short *) (pBuffer + pMetricsTOCEntry->offset + 6);
00493 nWidth = my_invert_byte_order_short(pMetricsData[n * 5 + 2], pMetricsTable->format & PCF_BYTE_MASK);
00494 nAscent = my_invert_byte_order_short(pMetricsData[n * 5 + 3], pMetricsTable->format & PCF_BYTE_MASK);
00495 nDescent = my_invert_byte_order_short(pMetricsData[n * 5 + 4], pMetricsTable->format & PCF_BYTE_MASK);
00496 }
00497
00498
00499 SetGlyph(n, pCoordinatesX, pCoordinatesY, nCoordinates, nWidth, nAscent, nDescent);
00500 }
00501
00502
00503 for (i = pEncodingTable->min_char_or_byte2; i <= pEncodingTable->max_char_or_byte2; i++)
00504 {
00505 const int nIndex = my_invert_byte_order_short(pEncodingData[i], pEncodingTable->format & PCF_BYTE_MASK);
00506 AddEncoding(i, nIndex);
00507 }
00508
00509
00510
00511
00512 m_nFontHeight = pAcceleratorTable->fontAscent + pAcceleratorTable->fontDescent;
00513
00514
00515 delete [] pCoordinatesX;
00516 delete [] pCoordinatesY;
00517 delete [] pBuffer;
00518
00519 return true;
00520 }
00521
00522 void CBitmapFont::DrawText(CByteImage *pImage, const char *pText, int x0, int y0, unsigned char r, unsigned char g, unsigned char b) const
00523 {
00524 const int nLength = (int) strlen(pText);
00525
00526 int x = x0, y = y0;
00527
00528 for (int i = 0; i < nLength; i++)
00529 {
00530 int *pCoordinatesX, *pCoordinatesY;
00531 int nCoordinates, nWidth;
00532
00533 if (pText[i] == '\n')
00534 {
00535 x = x0;
00536 y += m_nFontHeight;
00537 }
00538 else
00539 if (GetCharacterInformation(pText[i], pCoordinatesX, pCoordinatesY, nCoordinates, nWidth))
00540 {
00541 for (int j = 0; j < nCoordinates; j++)
00542 {
00543
00544 PrimitivesDrawer::DrawPoint(pImage, x + pCoordinatesX[j], y + pCoordinatesY[j], r, g, b);
00545 }
00546
00547 x += nWidth;
00548 }
00549 }
00550 }
00551
00552 void CBitmapFont::DrawText(CByteImage *pImage, const char *pText, int x, int y, Color::Color color) const
00553 {
00554 unsigned char r, g, b;
00555
00556 Color::GetRGBValues(color, r, g, b);
00557
00558 DrawText(pImage, pText, x, y, r, g, b);
00559 }