graphlcd-base/glcdgraphics/bitmap.c
changeset 4 df6a40031aa5
equal deleted inserted replaced
3:d0e62fc47285 4:df6a40031aa5
       
     1 /*
       
     2  * GraphLCD graphics library
       
     3  *
       
     4  * bitmap.c  -  cBitmap class
       
     5  *
       
     6  * based on graphlcd plugin 0.1.1 for the Video Disc Recorder
       
     7  *  (c) 2001-2004 Carsten Siebholz <c.siebholz AT t-online.de>
       
     8  *
       
     9  * This file is released under the GNU General Public License. Refer
       
    10  * to the COPYING file distributed with this package.
       
    11  *
       
    12  * (c) 2004 Andreas Regel <andreas.regel AT powarman.de>
       
    13  */
       
    14 
       
    15 #include <stdio.h>
       
    16 #include <stdlib.h>
       
    17 #include <string.h>
       
    18 #include <math.h>
       
    19 
       
    20 #include "bitmap.h"
       
    21 #include "common.h"
       
    22 #include "font.h"
       
    23 
       
    24 
       
    25 namespace GLCD
       
    26 {
       
    27 
       
    28 const unsigned char bitmask[8]  = {0x80, 0x40, 0x20, 0x10, 0x08, 0x04, 0x02, 0x01};
       
    29 const unsigned char bitmaskl[8] = {0x80, 0xc0, 0xe0, 0xf0, 0xf8, 0xfc, 0xfe, 0xff};
       
    30 const unsigned char bitmaskr[8] = {0xff, 0x7f, 0x3f, 0x1f, 0x0f, 0x07, 0x03, 0x01};
       
    31 
       
    32 cBitmap::cBitmap(int width, int height, unsigned char * data)
       
    33 :   width(width),
       
    34     height(height),
       
    35     bitmap(NULL)
       
    36 {
       
    37     // lines are byte aligned
       
    38     lineSize = (width + 7) / 8;
       
    39 
       
    40     bitmap = new unsigned char[lineSize * height];
       
    41     if (data)
       
    42         memcpy(bitmap, data, lineSize * height);
       
    43 }
       
    44 
       
    45 cBitmap::cBitmap(const cBitmap & b)
       
    46 {
       
    47     width = b.width;
       
    48     height = b.height;
       
    49     lineSize = b.lineSize;
       
    50     bitmap = new unsigned char[lineSize * height];
       
    51     if (b.bitmap)
       
    52         memcpy(bitmap, b.bitmap, lineSize * height);
       
    53 }
       
    54 
       
    55 cBitmap::~cBitmap()
       
    56 {
       
    57     delete[] bitmap;
       
    58 }
       
    59 
       
    60 void cBitmap::Clear()
       
    61 {
       
    62     memset(bitmap, 0, lineSize * height);
       
    63 }
       
    64 
       
    65 void cBitmap::Invert()
       
    66 {
       
    67     int i;
       
    68 
       
    69     for (i = 0; i < lineSize * height; i++)
       
    70     {
       
    71         bitmap[i] ^= 0xFF;
       
    72     }
       
    73 }
       
    74 
       
    75 void cBitmap::DrawPixel(int x, int y, eColor color)
       
    76 {
       
    77     if (x < 0 || x > width - 1)
       
    78         return;
       
    79     if (y < 0 || y > height - 1)
       
    80         return;
       
    81 
       
    82     unsigned char c = 0x80 >> (x % 8);
       
    83     if (color == clrBlack)
       
    84         bitmap[lineSize * y + x / 8] |= c;
       
    85     else
       
    86         bitmap[lineSize * y + x / 8] &= ~c;
       
    87 }
       
    88 
       
    89 void cBitmap::Draw8Pixels(int x, int y, unsigned char pixels, eColor color)
       
    90 {
       
    91     if (x < 0 || x > width - 1)
       
    92         return;
       
    93     if (y < 0 || y > height - 1)
       
    94         return;
       
    95 
       
    96     if (color == clrBlack)
       
    97         bitmap[lineSize * y + x / 8] |= pixels;
       
    98     else
       
    99         bitmap[lineSize * y + x / 8] &= ~pixels;
       
   100 }
       
   101 
       
   102 void cBitmap::DrawLine(int x1, int y1, int x2, int y2, eColor color)
       
   103 {
       
   104     int d, sx, sy, dx, dy;
       
   105     unsigned int ax, ay;
       
   106 
       
   107     dx = x2 - x1;
       
   108     ax = abs(dx) << 1;
       
   109     if (dx < 0)
       
   110         sx = -1;
       
   111     else
       
   112         sx = 1;
       
   113 
       
   114     dy = y2 - y1;
       
   115     ay = abs(dy) << 1;
       
   116     if (dy < 0)
       
   117         sy = -1;
       
   118     else
       
   119         sy = 1;
       
   120 
       
   121     DrawPixel(x1, y1, color);
       
   122     if (ax > ay)
       
   123     {
       
   124         d = ay - (ax >> 1);
       
   125         while (x1 != x2)
       
   126         {
       
   127             if (d >= 0)
       
   128             {
       
   129                 y1 += sy;
       
   130                 d -= ax;
       
   131             }
       
   132             x1 += sx;
       
   133             d += ay;
       
   134             DrawPixel(x1, y1, color);
       
   135         }
       
   136     }
       
   137     else
       
   138     {
       
   139         d = ax - (ay >> 1);
       
   140         while (y1 != y2)
       
   141         {
       
   142             if (d >= 0)
       
   143             {
       
   144                 x1 += sx;
       
   145                 d -= ay;
       
   146             }
       
   147             y1 += sy;
       
   148             d += ax;
       
   149             DrawPixel(x1, y1, color);
       
   150         }
       
   151     }
       
   152 }
       
   153 
       
   154 void cBitmap::DrawHLine(int x1, int y, int x2, eColor color)
       
   155 {
       
   156     sort(x1,x2);
       
   157 
       
   158     if (x1 / 8 == x2 / 8)
       
   159     {
       
   160         // start and end in the same byte
       
   161         Draw8Pixels(x1, y, bitmaskr[x1 % 8] & bitmaskl[x2 % 8], color);
       
   162     }
       
   163     else
       
   164     {
       
   165         // start and end in different bytes
       
   166         Draw8Pixels(x1, y, bitmaskr[x1 % 8], color);
       
   167         x1 = ((x1 + 8) / 8) * 8;
       
   168         while (x1 < (x2 / 8) * 8)
       
   169         {
       
   170             Draw8Pixels(x1, y, 0xff, color);
       
   171             x1 += 8;
       
   172         }
       
   173         Draw8Pixels(x2, y, bitmaskl[x2 % 8], color);
       
   174     }
       
   175 }
       
   176 
       
   177 void cBitmap::DrawVLine(int x, int y1, int y2, eColor color)
       
   178 {
       
   179     int y;
       
   180 
       
   181     sort(y1,y2);
       
   182 
       
   183     for (y = y1; y <= y2; y++)
       
   184         DrawPixel(x, y, color);
       
   185 }
       
   186 
       
   187 void cBitmap::DrawRectangle(int x1, int y1, int x2, int y2, eColor color, bool filled)
       
   188 {
       
   189     int y;
       
   190 
       
   191     sort(x1,x2);
       
   192     sort(y1,y2);
       
   193 
       
   194     if (!filled)
       
   195     {
       
   196         DrawHLine(x1, y1, x2, color);
       
   197         DrawVLine(x1, y1, y2, color);
       
   198         DrawHLine(x1, y2, x2, color);
       
   199         DrawVLine(x2, y1, y2, color);
       
   200     }
       
   201     else
       
   202     {
       
   203         for (y = y1; y <= y2; y++)
       
   204         {
       
   205             DrawHLine(x1, y, x2, color);
       
   206         }
       
   207     }
       
   208 }
       
   209 
       
   210 void cBitmap::DrawRoundRectangle(int x1, int y1, int x2, int y2, eColor color, bool filled, int type)
       
   211 {
       
   212     sort(x1,x2);
       
   213     sort(y1,y2);
       
   214 
       
   215     if (type > (x2 - x1) / 2)
       
   216         type = (x2 - x1) / 2;
       
   217     if (type > (y2 - y1) / 2)
       
   218         type = (y2 - y1) / 2;
       
   219 
       
   220     if (filled)
       
   221     {
       
   222         DrawHLine(x1 + type, y1, x2 - type, color);
       
   223         for (int y = y1 + 1; y < y1 + type; y++)
       
   224             DrawHLine(x1 + 1, y, x2 - 1, color);
       
   225         for (int y = y1 + type; y <= y2 - type; y++)
       
   226             DrawHLine(x1, y, x2, color);
       
   227         for (int y = y2 - type + 1; y < y2; y++)
       
   228             DrawHLine(x1 + 1, y, x2 - 1, color);
       
   229         DrawHLine(x1 + type, y2, x2 - type, color);
       
   230         if (type == 4)
       
   231         {
       
   232             // round the ugly fat box...
       
   233             DrawPixel(x1 + 1, y1 + 1, color == clrWhite ? clrBlack : clrWhite);
       
   234             DrawPixel(x1 + 1, y2 - 1, color == clrWhite ? clrBlack : clrWhite);
       
   235             DrawPixel(x2 - 1, y1 + 1, color == clrWhite ? clrBlack : clrWhite);
       
   236             DrawPixel(x2 - 1, y2 - 1, color == clrWhite ? clrBlack : clrWhite);
       
   237         }
       
   238     }
       
   239     else
       
   240     {
       
   241         DrawHLine(x1 + type, y1, x2 - type, color);
       
   242         DrawVLine(x1, y1 + type, y2 - type, color);
       
   243         DrawVLine(x2, y1 + type, y2 - type, color);
       
   244         DrawHLine(x1 + type, y2, x2 - type, color);
       
   245         if (type > 1)
       
   246         {
       
   247             DrawHLine(x1 + 1, y1 + 1, x1 + type - 1, color);
       
   248             DrawHLine(x2 - type + 1, y1 + 1, x2 - 1, color);
       
   249             DrawHLine(x1 + 1, y2 - 1, x1 + type - 1, color);
       
   250             DrawHLine(x2 - type + 1, y2 - 1, x2 - 1, color);
       
   251             DrawVLine(x1 + 1, y1 + 1, y1 + type - 1, color);
       
   252             DrawVLine(x1 + 1, y2 - 1, y2 - type + 1, color);
       
   253             DrawVLine(x2 - 1, y1 + 1, y1 + type - 1, color);
       
   254             DrawVLine(x2 - 1, y2 - 1, y2 - type + 1, color);
       
   255         }
       
   256     }
       
   257 }
       
   258 
       
   259 void cBitmap::DrawEllipse(int x1, int y1, int x2, int y2, eColor color, bool filled, int quadrants)
       
   260 {
       
   261     // Algorithm based on http://homepage.smc.edu/kennedy_john/BELIPSE.PDF
       
   262     int rx = x2 - x1;
       
   263     int ry = y2 - y1;
       
   264     int cx = (x1 + x2) / 2;
       
   265     int cy = (y1 + y2) / 2;
       
   266     switch (abs(quadrants))
       
   267     {
       
   268         case 0: rx /= 2; ry /= 2; break;
       
   269         case 1: cx = x1; cy = y2; break;
       
   270         case 2: cx = x2; cy = y2; break;
       
   271         case 3: cx = x2; cy = y1; break;
       
   272         case 4: cx = x1; cy = y1; break;
       
   273         case 5: cx = x1;          ry /= 2; break;
       
   274         case 6: cy = y2; rx /= 2; break;
       
   275         case 7: cx = x2;          ry /= 2; break;
       
   276         case 8: cy = y1; rx /= 2; break;
       
   277     }
       
   278     int TwoASquare = 2 * rx * rx;
       
   279     int TwoBSquare = 2 * ry * ry;
       
   280     int x = rx;
       
   281     int y = 0;
       
   282     int XChange = ry * ry * (1 - 2 * rx);
       
   283     int YChange = rx * rx;
       
   284     int EllipseError = 0;
       
   285     int StoppingX = TwoBSquare * rx;
       
   286     int StoppingY = 0;
       
   287     while (StoppingX >= StoppingY)
       
   288     {
       
   289         if (filled)
       
   290         {
       
   291             switch (quadrants)
       
   292             {
       
   293                 case  5: DrawRectangle(cx,     cy + y, cx + x, cy + y, color, filled); // no break
       
   294                 case  1: DrawRectangle(cx,     cy - y, cx + x, cy - y, color, filled); break;
       
   295                 case  7: DrawRectangle(cx - x, cy + y, cx,     cy + y, color, filled); // no break
       
   296                 case  2: DrawRectangle(cx - x, cy - y, cx,     cy - y, color, filled); break;
       
   297                 case  3: DrawRectangle(cx - x, cy + y, cx,     cy + y, color, filled); break;
       
   298                 case  4: DrawRectangle(cx,     cy + y, cx + x, cy + y, color, filled); break;
       
   299                 case  0:
       
   300                 case  6: DrawRectangle(cx - x, cy - y, cx + x, cy - y, color, filled); if (quadrants == 6) break;
       
   301                 case  8: DrawRectangle(cx - x, cy + y, cx + x, cy + y, color, filled); break;
       
   302                 case -1: DrawRectangle(cx + x, cy - y, x2,     cy - y, color, filled); break;
       
   303                 case -2: DrawRectangle(x1,     cy - y, cx - x, cy - y, color, filled); break;
       
   304                 case -3: DrawRectangle(x1,     cy + y, cx - x, cy + y, color, filled); break;
       
   305                 case -4: DrawRectangle(cx + x, cy + y, x2,     cy + y, color, filled); break;
       
   306             }
       
   307         }
       
   308         else
       
   309         {
       
   310             switch (quadrants)
       
   311             {
       
   312                 case  5: DrawPixel(cx + x, cy + y, color); // no break
       
   313                 case -1:
       
   314                 case  1: DrawPixel(cx + x, cy - y, color); break;
       
   315                 case  7: DrawPixel(cx - x, cy + y, color); // no break
       
   316                 case -2:
       
   317                 case  2: DrawPixel(cx - x, cy - y, color); break;
       
   318                 case -3:
       
   319                 case  3: DrawPixel(cx - x, cy + y, color); break;
       
   320                 case -4:
       
   321                 case  4: DrawPixel(cx + x, cy + y, color); break;
       
   322                 case  0:
       
   323                 case  6: DrawPixel(cx - x, cy - y, color); DrawPixel(cx + x, cy - y, color); if (quadrants == 6) break;
       
   324                 case  8: DrawPixel(cx - x, cy + y, color); DrawPixel(cx + x, cy + y, color); break;
       
   325             }
       
   326         }
       
   327         y++;
       
   328         StoppingY += TwoASquare;
       
   329         EllipseError += YChange;
       
   330         YChange += TwoASquare;
       
   331         if (2 * EllipseError + XChange > 0)
       
   332         {
       
   333             x--;
       
   334             StoppingX -= TwoBSquare;
       
   335             EllipseError += XChange;
       
   336             XChange += TwoBSquare;
       
   337         }
       
   338     }
       
   339     x = 0;
       
   340     y = ry;
       
   341     XChange = ry * ry;
       
   342     YChange = rx * rx * (1 - 2 * ry);
       
   343     EllipseError = 0;
       
   344     StoppingX = 0;
       
   345     StoppingY = TwoASquare * ry;
       
   346     while (StoppingX <= StoppingY)
       
   347     {
       
   348         if (filled)
       
   349         {
       
   350             switch (quadrants)
       
   351             {
       
   352                 case  5: DrawRectangle(cx,     cy + y, cx + x, cy + y, color, filled); // no break
       
   353                 case  1: DrawRectangle(cx,     cy - y, cx + x, cy - y, color, filled); break;
       
   354                 case  7: DrawRectangle(cx - x, cy + y, cx,     cy + y, color, filled); // no break
       
   355                 case  2: DrawRectangle(cx - x, cy - y, cx,     cy - y, color, filled); break;
       
   356                 case  3: DrawRectangle(cx - x, cy + y, cx,     cy + y, color, filled); break;
       
   357                 case  4: DrawRectangle(cx,     cy + y, cx + x, cy + y, color, filled); break;
       
   358                 case  0:
       
   359                 case  6: DrawRectangle(cx - x, cy - y, cx + x, cy - y, color, filled); if (quadrants == 6) break;
       
   360                 case  8: DrawRectangle(cx - x, cy + y, cx + x, cy + y, color, filled); break;
       
   361                 case -1: DrawRectangle(cx + x, cy - y, x2,     cy - y, color, filled); break;
       
   362                 case -2: DrawRectangle(x1,     cy - y, cx - x, cy - y, color, filled); break;
       
   363                 case -3: DrawRectangle(x1,     cy + y, cx - x, cy + y, color, filled); break;
       
   364                 case -4: DrawRectangle(cx + x, cy + y, x2,     cy + y, color, filled); break;
       
   365             }
       
   366         }
       
   367         else
       
   368         {
       
   369             switch (quadrants)
       
   370             {
       
   371                 case  5: DrawPixel(cx + x, cy + y, color); // no break
       
   372                 case -1:
       
   373                 case  1: DrawPixel(cx + x, cy - y, color); break;
       
   374                 case  7: DrawPixel(cx - x, cy + y, color); // no break
       
   375                 case -2:
       
   376                 case  2: DrawPixel(cx - x, cy - y, color); break;
       
   377                 case -3:
       
   378                 case  3: DrawPixel(cx - x, cy + y, color); break;
       
   379                 case -4:
       
   380                 case  4: DrawPixel(cx + x, cy + y, color); break;
       
   381                 case  0:
       
   382                 case  6: DrawPixel(cx - x, cy - y, color); DrawPixel(cx + x, cy - y, color); if (quadrants == 6) break;
       
   383                 case  8: DrawPixel(cx - x, cy + y, color); DrawPixel(cx + x, cy + y, color); break;
       
   384             }
       
   385         }
       
   386         x++;
       
   387         StoppingX += TwoBSquare;
       
   388         EllipseError += XChange;
       
   389         XChange += TwoBSquare;
       
   390         if (2 * EllipseError + YChange > 0)
       
   391         {
       
   392             y--;
       
   393             StoppingY -= TwoASquare;
       
   394             EllipseError += YChange;
       
   395             YChange += TwoASquare;
       
   396         }
       
   397     }
       
   398 }
       
   399 
       
   400 void cBitmap::DrawSlope(int x1, int y1, int x2, int y2, eColor color, int type)
       
   401 {
       
   402     bool upper    = type & 0x01;
       
   403     bool falling  = type & 0x02;
       
   404     bool vertical = type & 0x04;
       
   405     if (vertical)
       
   406     {
       
   407         for (int y = y1; y <= y2; y++)
       
   408         {
       
   409             double c = cos((y - y1) * M_PI / (y2 - y1 + 1));
       
   410             if (falling)
       
   411                 c = -c;
       
   412             int x = int((x2 - x1 + 1) * c / 2);
       
   413             if (upper && !falling || !upper && falling)
       
   414                 DrawRectangle(x1, y, (x1 + x2) / 2 + x, y, color, true);
       
   415             else
       
   416                 DrawRectangle((x1 + x2) / 2 + x, y, x2, y, color, true);
       
   417         }
       
   418     }
       
   419     else
       
   420     {
       
   421         for (int x = x1; x <= x2; x++)
       
   422         {
       
   423             double c = cos((x - x1) * M_PI / (x2 - x1 + 1));
       
   424             if (falling)
       
   425                 c = -c;
       
   426             int y = int((y2 - y1 + 1) * c / 2);
       
   427             if (upper)
       
   428                 DrawRectangle(x, y1, x, (y1 + y2) / 2 + y, color, true);
       
   429             else
       
   430                 DrawRectangle(x, (y1 + y2) / 2 + y, x, y2, color, true);
       
   431         }
       
   432     }
       
   433 }
       
   434 
       
   435 void cBitmap::DrawBitmap(int x, int y, const cBitmap & bitmap, eColor color)
       
   436 {
       
   437     unsigned char cl = 0;
       
   438     int xt, yt;
       
   439     const unsigned char * data = bitmap.Data();
       
   440     unsigned short temp;
       
   441     int h, w;
       
   442 
       
   443     w = bitmap.Width();
       
   444     h = bitmap.Height();
       
   445 
       
   446     if (data)
       
   447     {
       
   448         if (!(x % 8))
       
   449         {
       
   450             // Bitmap is byte alligned (0,8,16,...)
       
   451             for (yt = 0; yt < h; yt++)
       
   452             {
       
   453                 for (xt = 0; xt < (w / 8); xt++)
       
   454                 {
       
   455                     cl = *data;
       
   456                     Draw8Pixels(x + (xt * 8), y + yt, cl, color);
       
   457                     data++;
       
   458                 }
       
   459                 if (w % 8)
       
   460                 {
       
   461                     cl = *data;
       
   462                     Draw8Pixels(x + ((w / 8) * 8), y + yt, cl & bitmaskl[w % 8 - 1], color);
       
   463                     data++;
       
   464                 }
       
   465             }
       
   466         }
       
   467         else
       
   468         {
       
   469             // Bitmap is not byte alligned
       
   470             for (yt = 0; yt < h; yt++)
       
   471             {
       
   472                 temp = 0;
       
   473                 for (xt = 0; xt < (w + (x % 8)) / 8; xt++)
       
   474                 {
       
   475                     cl = *(data + yt * ((w + 7) / 8) + xt);
       
   476                     temp = temp | ((unsigned short) cl << (8 - (x % 8)));
       
   477                     cl = (temp & 0xff00) >> 8;
       
   478                     if (!xt)
       
   479                     {
       
   480                         // first byte
       
   481                         Draw8Pixels(x - (x % 8) + (xt * 8), y + yt, cl & bitmaskr[x % 8], color);
       
   482                     }
       
   483                     else
       
   484                     {
       
   485                         // not the first byte
       
   486                         Draw8Pixels(x - (x % 8) + (xt * 8), y + yt, cl, color);
       
   487                     }
       
   488                     temp <<= 8;
       
   489                 }
       
   490                 if ((w + (x % 8) + 7) / 8 != (w + (x % 8)) / 8)
       
   491                 {
       
   492                     // print the rest
       
   493                     cl = *(data + (yt + 1) * ((w + 7) / 8) - 1);
       
   494                     temp = temp | ((unsigned short) cl << (8 - (x % 8)));
       
   495                     cl = (temp & 0xff00) >> 8;
       
   496                     Draw8Pixels(x - (x % 8) + (((w + (x % 8)) / 8) * 8), y + yt, cl & bitmaskl[(w + x) % 8 - 1], color);
       
   497                 }
       
   498             }
       
   499         }
       
   500     }
       
   501 }
       
   502 
       
   503 int cBitmap::DrawText(int x, int y, int xmax, const std::string & text, const cFont * font,
       
   504                       eColor color, bool proportional, int skipPixels)
       
   505 {
       
   506     int xt;
       
   507     int yt;
       
   508     int i;
       
   509     char c;
       
   510     int start;
       
   511 
       
   512     clip(x, 0, width - 1);
       
   513     clip(y, 0, height - 1);
       
   514 
       
   515     xt = x;
       
   516     yt = y;
       
   517     start = 0;
       
   518 
       
   519     if (text.length() > 0)
       
   520     {
       
   521         if (skipPixels > 0)
       
   522         {
       
   523             if (!proportional)
       
   524             {
       
   525                 if (skipPixels >= (int) text.length() * font->TotalWidth())
       
   526                     start = text.length();
       
   527                 else
       
   528                     while (skipPixels > font->TotalWidth())
       
   529                     {
       
   530                         skipPixels -= font->TotalWidth();
       
   531                         start++;
       
   532                     }
       
   533             }
       
   534             else
       
   535             {
       
   536                 if (skipPixels >= font->Width(text))
       
   537                     start = text.length();
       
   538                 else
       
   539                     while (skipPixels > font->Width(text[start]))
       
   540                     {
       
   541                         skipPixels -= font->Width(text[start]);
       
   542                         skipPixels -= font->SpaceBetween();
       
   543                         start++;
       
   544                     }
       
   545             }
       
   546         }
       
   547         for (i = start; i < (int) text.length(); i++)
       
   548         {
       
   549             c = text[i];
       
   550             if (xt > xmax)
       
   551             {
       
   552                 i = text.length();
       
   553             }
       
   554             else
       
   555             {
       
   556                 if (!proportional)
       
   557                 {
       
   558                     if (skipPixels > 0)
       
   559                     {
       
   560                         DrawCharacter(xt, yt, xmax, c, font, color, skipPixels);
       
   561                         xt += font->TotalWidth() - skipPixels;
       
   562                         skipPixels = 0;
       
   563                     }
       
   564                     else
       
   565                     {
       
   566                         DrawCharacter(xt, yt, xmax, c, font, color);
       
   567                         xt += font->TotalWidth();
       
   568                     }
       
   569                 }
       
   570                 else
       
   571                 {
       
   572                     if (skipPixels > 0)
       
   573                     {
       
   574                         xt += DrawCharacter(xt, yt, xmax, c, font, color, skipPixels);
       
   575                         skipPixels = 0;
       
   576                     }
       
   577                     else
       
   578                     {
       
   579                         xt += DrawCharacter(xt, yt, xmax, c, font, color);
       
   580                     }
       
   581                     if (xt <= xmax)
       
   582                     {
       
   583                         xt += font->SpaceBetween();
       
   584                     }
       
   585                 }
       
   586             }
       
   587         }
       
   588     }
       
   589     return xt;
       
   590 }
       
   591 
       
   592 int cBitmap::DrawCharacter(int x, int y, int xmax, char c, const cFont * font,
       
   593                            eColor color, int skipPixels)
       
   594 {
       
   595     const cBitmap * charBitmap;
       
   596 
       
   597     clip(x, 0, width - 1);
       
   598     clip(y, 0, height - 1);
       
   599 
       
   600     charBitmap = font->GetCharacter(c);
       
   601     if (charBitmap)
       
   602     {
       
   603         cBitmap * drawBitmap = charBitmap->SubBitmap(skipPixels, 0, xmax - x + skipPixels, charBitmap->Height() - 1);
       
   604         if (drawBitmap)
       
   605             DrawBitmap(x, y, *drawBitmap, color);
       
   606         delete drawBitmap;
       
   607         return charBitmap->Width() - skipPixels;
       
   608     }
       
   609     return 0;
       
   610 }
       
   611 
       
   612 unsigned char cBitmap::GetPixel(int x, int y) const
       
   613 {
       
   614     unsigned char value;
       
   615 
       
   616     value = bitmap[y * lineSize + x / 8];
       
   617     value = (value >> (7 - (x % 8))) & 1;
       
   618     return value;
       
   619 }
       
   620 
       
   621 cBitmap * cBitmap::SubBitmap(int x1, int y1, int x2, int y2) const
       
   622 {
       
   623     int w, h;
       
   624     int xt, yt;
       
   625     cBitmap * bmp;
       
   626     unsigned char cl;
       
   627     unsigned char * data;
       
   628     unsigned short temp;
       
   629 
       
   630     sort(x1,x2);
       
   631     sort(y1,y2);
       
   632     if (x1 < 0 || x1 > width - 1)
       
   633         return NULL;
       
   634     if (y1 < 0 || y1 > height - 1)
       
   635         return NULL;
       
   636     clip(x2, 0, width - 1);
       
   637     clip(y2, 0, height - 1);
       
   638 
       
   639     w = x2 - x1 + 1;
       
   640     h = y2 - y1 + 1;
       
   641     bmp = new cBitmap(w, h);
       
   642     if (!bmp || !bmp->Data())
       
   643         return NULL;
       
   644     bmp->Clear();
       
   645     if (x1 % 8 == 0)
       
   646     {
       
   647         // Bitmap is byte alligned (0,8,16,...)
       
   648         for (yt = 0; yt < h; yt++)
       
   649         {
       
   650             data = &bitmap[(y1 + yt) * lineSize + x1 / 8];
       
   651             for (xt = 0; xt < (w / 8) * 8; xt += 8)
       
   652             {
       
   653                 cl = *data;
       
   654                 bmp->Draw8Pixels(xt, yt, cl, clrBlack);
       
   655                 data++;
       
   656             }
       
   657             if (w % 8 != 0)
       
   658             {
       
   659                 cl = *data;
       
   660                 bmp->Draw8Pixels(xt, yt, cl & bitmaskl[w % 8 - 1], clrBlack);
       
   661             }
       
   662         }
       
   663     }
       
   664     else
       
   665     {
       
   666         // Bitmap is not byte alligned
       
   667         for (yt = 0; yt < h; yt++)
       
   668         {
       
   669             temp = 0;
       
   670             data = &bitmap[(y1 + yt) * lineSize + x1 / 8];
       
   671             for (xt = 0; xt <= ((w / 8)) * 8; xt += 8)
       
   672             {
       
   673                 cl = *data;
       
   674                 temp = temp | ((unsigned short) cl << (x1 % 8));
       
   675                 cl = (temp & 0xff00) >> 8;
       
   676                 if (xt > 0)
       
   677                 {
       
   678                     bmp->Draw8Pixels(xt - 8, yt, cl, clrBlack);
       
   679                 }
       
   680                 temp <<= 8;
       
   681                 data++;
       
   682             }
       
   683             if (w % 8 != 0)
       
   684             {
       
   685                 // print the rest
       
   686                 if (8 - (x1 % 8) < w % 8)
       
   687                 {
       
   688                     cl = *data;
       
   689                     temp = temp | ((unsigned short) cl << (x1 % 8));
       
   690                 }
       
   691                 cl = (temp & 0xff00) >> 8;
       
   692                 bmp->Draw8Pixels(xt - 8, yt, cl & bitmaskl[(w % 8) - 1], clrBlack);
       
   693             }
       
   694         }
       
   695     }
       
   696     return bmp;
       
   697 }
       
   698 
       
   699 bool cBitmap::LoadPBM(const std::string & fileName)
       
   700 {
       
   701     FILE * pbmFile;
       
   702     char str[32];
       
   703     int i;
       
   704     int ch;
       
   705     int w;
       
   706     int h;
       
   707 
       
   708     pbmFile = fopen(fileName.c_str(), "rb");
       
   709     if (!pbmFile)
       
   710         return false;
       
   711 
       
   712     i = 0;
       
   713     while ((ch = getc(pbmFile)) != EOF && i < 31)
       
   714     {
       
   715         if (ch == ' ' || ch == '\t' || ch == '\n' || ch == '\r')
       
   716             break;
       
   717         str[i] = ch;
       
   718         i++;
       
   719     }
       
   720     if (ch == EOF)
       
   721     {
       
   722         fclose(pbmFile);
       
   723         return false;
       
   724     }
       
   725     str[i] = 0;
       
   726     if (strcmp(str, "P4") != 0)
       
   727         return false;
       
   728 
       
   729     while ((ch = getc(pbmFile)) == '#')
       
   730     {
       
   731         while ((ch = getc(pbmFile)) != EOF)
       
   732         {
       
   733             if (ch == '\n' || ch == '\r')
       
   734                 break;
       
   735         }
       
   736     }
       
   737     if (ch == EOF)
       
   738     {
       
   739         fclose(pbmFile);
       
   740         return false;
       
   741     }
       
   742     i = 0;
       
   743     str[i] = ch;
       
   744     i += 1;
       
   745     while ((ch = getc(pbmFile)) != EOF && i < 31)
       
   746     {
       
   747         if (ch == ' ' || ch == '\t' || ch == '\n' || ch == '\r')
       
   748             break;
       
   749         str[i] = ch;
       
   750         i++;
       
   751     }
       
   752     if (ch == EOF)
       
   753     {
       
   754         fclose(pbmFile);
       
   755         return false;
       
   756     }
       
   757     str[i] = 0;
       
   758     w = atoi(str);
       
   759 
       
   760     i = 0;
       
   761     while ((ch = getc(pbmFile)) != EOF && i < 31)
       
   762     {
       
   763         if (ch == ' ' || ch == '\t' || ch == '\n' || ch == '\r')
       
   764             break;
       
   765         str[i] = ch;
       
   766         i++;
       
   767     }
       
   768     if (ch == EOF)
       
   769     {
       
   770         fclose(pbmFile);
       
   771         return false;
       
   772     }
       
   773     str[i] = 0;
       
   774     h = atoi(str);
       
   775 
       
   776     delete[] bitmap;
       
   777     width = w;
       
   778     height = h;
       
   779     // lines are byte aligned
       
   780     lineSize = (width + 7) / 8;
       
   781     bitmap = new unsigned char[lineSize * height];
       
   782     fread(bitmap, lineSize * height, 1, pbmFile);
       
   783     fclose(pbmFile);
       
   784 
       
   785     return true;
       
   786 }
       
   787 
       
   788 void cBitmap::SavePBM(const std::string & fileName)
       
   789 {
       
   790     int i;
       
   791     char str[32];
       
   792     FILE * fp;
       
   793 
       
   794     fp = fopen(fileName.c_str(), "wb");
       
   795     if (fp)
       
   796     {
       
   797         sprintf(str, "P4\n%d %d\n", width, height);
       
   798         fwrite(str, strlen(str), 1, fp);
       
   799         for (i = 0; i < lineSize * height; i++)
       
   800         {
       
   801             fwrite(&bitmap[i], 1, 1, fp);
       
   802         }
       
   803         fclose(fp);
       
   804     }
       
   805 }
       
   806 
       
   807 } // end of namespace