BitmapFont.cpp
Go to the documentation of this file.
00001 // ****************************************************************************
00002 // This file is part of the Integrating Vision Toolkit (IVT).
00003 //
00004 // The IVT is maintained by the Karlsruhe Institute of Technology (KIT)
00005 // (www.kit.edu) in cooperation with the company Keyetech (www.keyetech.de).
00006 //
00007 // Copyright (C) 2014 Karlsruhe Institute of Technology (KIT).
00008 // All rights reserved.
00009 //
00010 // Redistribution and use in source and binary forms, with or without
00011 // modification, are permitted provided that the following conditions are met:
00012 //
00013 // 1. Redistributions of source code must retain the above copyright
00014 //    notice, this list of conditions and the following disclaimer.
00015 //
00016 // 2. Redistributions in binary form must reproduce the above copyright
00017 //    notice, this list of conditions and the following disclaimer in the
00018 //    documentation and/or other materials provided with the distribution.
00019 //
00020 // 3. Neither the name of the KIT nor the names of its contributors may be
00021 //    used to endorse or promote products derived from this software
00022 //    without specific prior written permission.
00023 //
00024 // THIS SOFTWARE IS PROVIDED BY THE KIT AND CONTRIBUTORS “AS IS” AND ANY
00025 // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
00026 // WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
00027 // DISCLAIMED. IN NO EVENT SHALL THE KIT OR CONTRIBUTORS BE LIABLE FOR ANY
00028 // DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
00029 // (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
00030 // LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
00031 // ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
00032 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
00033 // THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
00034 // ****************************************************************************
00035 // ****************************************************************************
00036 // Filename:  BitmapFont.cpp
00037 // Copyright: Keyetech UG (haftungsbeschraenkt)
00038 // Author:    Pedram Azad
00039 // Date:      17.12.2012
00040 // ****************************************************************************
00041 
00042 
00043 // ****************************************************************************
00044 // Includes
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 // Defines
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)          /* See the bitmap table for explanation */
00076 #define PCF_BYTE_MASK           (1<<2)          /* If set then Most Sig Byte First */
00077 #define PCF_BIT_MASK            (1<<3)          /* If set then Most Sig Bit First */
00078 #define PCF_SCAN_UNIT_MASK      (3<<4)          /* See the bitmap table for explanation */
00079 
00080 
00081 // ****************************************************************************
00082 // Struct definitions
00083 // ****************************************************************************
00084 
00085 struct TOCEntry
00086 {
00087     int type;           // indicates which table
00088     int format;         // indicates how the data are formatted in the table
00089     int size;           // in bytes
00090     int offset;         // from start of file
00091 };
00092 
00093 struct PCFMetricsTable
00094 {
00095         int format;
00096         short metrics_count;
00097 };
00098 
00099 struct PCFEncodingTable
00100 {
00101         int format;                                             // always stored with least significant byte first
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;                                             // always stored with least significant byte first
00112         unsigned char noOverlap;
00113         unsigned char constantMetrics;
00114         unsigned char terminalFont;
00115         unsigned char constantWidth;            // monospace font like courier
00116         unsigned char inkInside;
00117         unsigned char inkMetrics;
00118         unsigned char drawDirection;            // 0 =>left to right, 1 => right to left
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 // CBitmapFont
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         // copy coordinates
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         // allocate memory for file contents
00313         unsigned char *pBuffer = new unsigned char[nFileSize];
00314         
00315         // read file into buffer
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         // compare
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         // read accelerator table
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         // read metrics table
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         // read encoding table
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         // read bitmap table
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         // invert byte order if needed
00422         //for (int i = 0; i < nGlyphs; i++)
00423         //      pGlyphOffsets[i] = my_invert_byte_order_int(pGlyphOffsets[i], nBitmapFormat & PCF_BYTE_MASK);
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         // initialize
00451         Init(nGlyphs);
00452 
00453         // allocate memory for maximum number of coordinates
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                 // collect coordinates
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                 // read metric data
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                 // store coordinates and other information
00499                 SetGlyph(n, pCoordinatesX, pCoordinatesY, nCoordinates, nWidth, nAscent, nDescent);
00500         }
00501 
00502         // set encoding table
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         //printf("\n%i glyphs with %i lines each with %i bytes each (%i = %i)\n", nGlyphs, nLinesPerGlyph, nBytesPerLine, nGlyphs * nLinesPerGlyph * nBytesPerLine, nBitmapSize);
00510 
00511         // set some attributes
00512         m_nFontHeight = pAcceleratorTable->fontAscent + pAcceleratorTable->fontDescent;
00513         
00514         // free memory
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                                         // DrawPoint is fail safe
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 }


asr_ivt
Author(s): Allgeyer Tobias, Hutmacher Robin, Kleinert Daniel, Meißner Pascal, Scholz Jonas, Stöckle Patrick
autogenerated on Thu Jun 6 2019 21:46:57