graphlcd-base/tools/convpic/bmp.c
author cpresser@slime-ws
Sat, 26 Jul 2008 14:22:38 +0200
changeset 25 96f051df5d60
parent 4 df6a40031aa5
permissions -rw-r--r--
added eeprom code
     1 /**
     2  *  GraphLCD plugin for the Video Disk Recorder
     3  *
     4  *  bmp.c  -  bmp logo class
     5  *
     6  *  (C) 2004 Andreas Brachold <vdr04 AT deltab de>
     7  *  (C) 2001-2004 Carsten Siebholz <c.siebholz AT t-online de>
     8  **/
     9 
    10 /***************************************************************************
    11  *                                                                         *
    12  *   This program is free software; you can redistribute it and/or modify  *
    13  *   it under the terms of the GNU General Public License as published by  *
    14  *   the Free Software Foundation; either version 2 of the License, or     *
    15  *   (at your option) any later version.                                   *
    16  *                                                                         *
    17  *   This program is distributed in the hope that it will be useful,       *
    18  *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
    19  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
    20  *   GNU General Public License for more details.                          *
    21  *                                                                         *
    22  *   You should have received a copy of the GNU General Public License     *
    23  *   along with this program;                                              *
    24  *   if not, write to the Free Software Foundation, Inc.,                  *
    25  *   59 Temple Place, Suite 330, Boston, MA  02111-1307  USA               *
    26  *                                                                         *
    27  ***************************************************************************/
    28 
    29 #include <stdio.h>
    30 #include <stdint.h>
    31 #include <string.h>
    32 
    33 #include <string>
    34 
    35 #include <glcdgraphics/bitmap.h>
    36 #include <glcdgraphics/image.h>
    37 
    38 #include "bmp.h"
    39 
    40 
    41 #pragma pack(1)
    42 typedef struct BMPH {
    43     uint16_t  bmpIdentifier;
    44     uint32_t  bmpFileSize;
    45     uint32_t  bmpReserved;
    46     uint32_t  bmpBitmapDataOffset;
    47     uint32_t  bmpBitmapHeaderSize;
    48     uint32_t  bmpWidth;
    49     uint32_t  bmpHeight;
    50     uint16_t  bmpPlanes;
    51     uint16_t  bmpBitsPerPixel;
    52     uint32_t  bmpCompression;
    53     uint32_t  bmpBitmapDataSize;
    54     uint32_t  bmpHResolution;
    55     uint32_t  bmpVResolution;
    56     uint32_t  bmpColors;
    57     uint32_t  bmpImportantColors;
    58 } BMPHEADER;  // 54 bytes
    59 
    60 typedef struct RGBQ {
    61     uint8_t  rgbBlue;
    62     uint8_t  rgbGreen;
    63     uint8_t  rgbRed;
    64     uint8_t  rgbReserved;
    65 } RGBQUAD;    // 4 bytes
    66 #pragma pack()
    67 
    68 
    69 uint8_t bitmask[8]  = {0x80, 0x40, 0x20, 0x10, 0x08, 0x04, 0x02, 0x01};
    70 uint8_t bitmaskl[8] = {0x80, 0xc0, 0xe0, 0xf0, 0xf8, 0xfc, 0xfe, 0xff};
    71 uint8_t bitmaskr[8] = {0xff, 0x7f, 0x3f, 0x1f, 0x0f, 0x07, 0x03, 0x01};
    72 
    73 cBMPFile::cBMPFile()
    74 {
    75 }
    76 
    77 cBMPFile::~cBMPFile()
    78 {
    79 }
    80 
    81 bool cBMPFile::Load(GLCD::cImage & image, const std::string & fileName)
    82 {
    83     FILE         *fIN;
    84     BMPHEADER     bmpHeader;
    85     RGBQUAD      *pPalette;
    86     char         *pByte;
    87     char          Dummy;
    88     long          iNumColors;
    89     long          iSize;
    90     uint32_t      x, y;
    91     uint16_t      iRead;
    92     uint8_t *  bitmap = NULL;
    93     bool  bInvert = false;
    94 
    95     if (fileName.length() > 0)
    96     {
    97         fIN = fopen(fileName.c_str(), "rb");
    98         if (fIN)
    99         {
   100             if (fread(&bmpHeader, sizeof(BMPHEADER), 1, fIN)!=1)
   101             {
   102                 fclose(fIN);
   103                 return false;
   104             }
   105 
   106             // check for Windows BMP
   107             if (bmpHeader.bmpBitmapHeaderSize != 0x00000028 )
   108             {
   109                 fprintf(stderr, "ERROR: only Windows BMP images are allowed.\n");
   110                 fclose(fIN);
   111                 return false;
   112             }
   113 
   114             // check for 2 color
   115             iNumColors = (1 << bmpHeader.bmpBitsPerPixel);
   116             if (iNumColors != 2)
   117             {
   118                 fprintf(stderr, "ERROR: the image has %ld colors, but only images with 2 colors are allowed.\n", iNumColors);
   119                 fclose(fIN);
   120                 return false;
   121             }
   122 
   123             iSize = bmpHeader.bmpHeight * bmpHeader.bmpWidth;
   124 
   125             pPalette = (RGBQUAD *) malloc( iNumColors*sizeof(RGBQUAD));
   126             if (!pPalette)
   127             {
   128                 fprintf(stderr, "ERROR: cannot allocate memory\n");
   129                 fclose(fIN);
   130                 return false;
   131             }
   132 
   133             if (fread( pPalette, iNumColors*sizeof(RGBQUAD), 1, fIN)!=1)
   134             {
   135                 free(pPalette);
   136                 fclose(fIN);
   137                 return false;
   138             }
   139 
   140             // check colors
   141             if (pPalette->rgbBlue+pPalette->rgbGreen+pPalette->rgbRed <
   142                     (pPalette+1)->rgbBlue+(pPalette+1)->rgbGreen+(pPalette+1)->rgbRed)
   143             {
   144                 // index 0 represents 'black', index 1 'white'
   145                 bInvert = !bInvert;
   146             }
   147             else
   148             {
   149                 // index 0 represents 'white', index 1 'black'
   150             }
   151 
   152             if (fseek(fIN, bmpHeader.bmpBitmapDataOffset, SEEK_SET)==EOF)
   153             {
   154                 free(pPalette);
   155                 fclose(fIN);
   156                 return false;
   157             }
   158 
   159             switch (bmpHeader.bmpCompression)
   160             {
   161                 case 0: // BI_RGB       no compression
   162                     image.Clear();
   163                     image.SetWidth(bmpHeader.bmpWidth);
   164                     image.SetHeight(bmpHeader.bmpHeight);
   165                     image.SetDelay(100);
   166                     bitmap = new unsigned char[bmpHeader.bmpHeight * ((bmpHeader.bmpWidth + 7) / 8)];
   167                     if (!bitmap)
   168                     {
   169                         fprintf(stderr, "ERROR: cannot allocate memory\n");
   170                         free(pPalette);
   171                         fclose(fIN);
   172                         image.Clear();
   173                         return false;
   174                     }
   175 
   176                     for (y = bmpHeader.bmpHeight; y > 0; y--)
   177                     {
   178                         pByte = (char*)bitmap + (y-1)*((bmpHeader.bmpWidth+7)/8);
   179                         iRead = 0;
   180                         for (x = 0; x < bmpHeader.bmpWidth / 8; x++)
   181                         {
   182                             if (fread(pByte, sizeof(char), 1, fIN) != 1)
   183                             {
   184                                 delete[] bitmap;
   185                                 free(pPalette);
   186                                 fclose(fIN);
   187                                 image.Clear();
   188                                 return false;
   189                             }
   190                             iRead++;
   191                             if (bInvert)
   192                                 *pByte = *pByte ^ 0xff;
   193                             pByte++;
   194                         }
   195 
   196                         if (bmpHeader.bmpWidth % 8)
   197                         {
   198                             if (fread(pByte, sizeof(char), 1, fIN) != 1)
   199                             {
   200                                 delete [] bitmap;
   201                                 free(pPalette);
   202                                 fclose(fIN);
   203                                 image.Clear();
   204                                 return false;
   205                             }
   206                             iRead++;
   207                             if (bInvert)
   208                                 *pByte = *pByte^0xff;
   209                             *pByte = *pByte & bitmaskl[bmpHeader.bmpWidth%8];
   210                             pByte++;
   211                         }
   212 
   213                         // Scan line must be 4-byte-alligned
   214                         while (iRead % 4)
   215                         {
   216                             if (fread(&Dummy, sizeof(char), 1, fIN) != 1)
   217                             {
   218                                 delete [] bitmap;
   219                                 free(pPalette);
   220                                 fclose(fIN);
   221                                 image.Clear();
   222                                 return false;
   223                             }
   224                             iRead++;
   225                         }
   226                     }
   227                     image.AddBitmap(new GLCD::cBitmap(bmpHeader.bmpWidth, bmpHeader.bmpHeight, bitmap));
   228                     break;
   229                 case 1: // BI_RLE4      RLE 4bit/pixel
   230                 case 2: // BI_RLE8      RLE 8bit/pixel
   231                 case 3: // BI_BITFIELDS
   232                 default:
   233                     fprintf(stderr, "ERROR: only uncompressed RGB images are allowed.\n");
   234 
   235                     free(pPalette);
   236                     fclose(fIN);
   237                     return false;
   238             }
   239             fclose(fIN);
   240         }
   241         else
   242         {
   243             fprintf(stderr, "ERROR: cannot open picture %s\n", fileName.c_str());
   244         }
   245     }
   246     else
   247     {
   248         fprintf(stderr, "ERROR: no FileName given!\n");
   249     }
   250     return true;
   251 }
   252 
   253 bool cBMPFile::Save(const GLCD::cBitmap * bitmap, const std::string & fileName)
   254 {
   255     FILE         *fOut;
   256     BMPHEADER     bmpHeader;
   257     RGBQUAD       bmpColor1, bmpColor2;
   258     uint32_t      dBDO, dBDSx, dBDS;
   259     char         *pByte;
   260     char          Dummy = 0x00;
   261     uint32_t      x, y;
   262     uint16_t      iWrote;
   263     const uint8_t * bmpdata = bitmap->Data();
   264 
   265     if (bitmap
   266         && bitmap->Width() > 0
   267         && bitmap->Height() > 0)
   268     {
   269         memset(&bmpHeader, 0, sizeof(BMPHEADER));
   270 
   271         dBDO = sizeof(BMPHEADER)+2*sizeof(RGBQUAD);
   272         dBDSx = ((bitmap->Width() + 7) / 8 + 3) & 0xfffffffc;
   273         dBDS = dBDSx * bitmap->Height();
   274 
   275         bmpHeader.bmpIdentifier       = 0x4d42; // "BM"
   276         bmpHeader.bmpFileSize         = dBDO + dBDS;
   277         bmpHeader.bmpBitmapDataOffset = dBDO;
   278         bmpHeader.bmpBitmapHeaderSize = 0x28;
   279         bmpHeader.bmpWidth            = bitmap->Width();
   280         bmpHeader.bmpHeight           = bitmap->Height();
   281         bmpHeader.bmpPlanes           = 0x01;
   282         bmpHeader.bmpBitsPerPixel     = 0x01;
   283         bmpHeader.bmpCompression      = 0x00;
   284         bmpHeader.bmpBitmapDataSize   = dBDS;
   285         bmpHeader.bmpHResolution      = 0xb13;  // 72dpi
   286         bmpHeader.bmpVResolution      = 0xb13;  // 72dpi
   287         bmpHeader.bmpColors           = 0x02;
   288         bmpHeader.bmpImportantColors  = 0x02;
   289 
   290         bmpColor1.rgbBlue     = 0x00;
   291         bmpColor1.rgbGreen    = 0x00;
   292         bmpColor1.rgbRed      = 0x00;
   293         bmpColor1.rgbReserved = 0x00;
   294         bmpColor2.rgbBlue     = 0xff;
   295         bmpColor2.rgbGreen    = 0xff;
   296         bmpColor2.rgbRed      = 0xff;
   297         bmpColor2.rgbReserved = 0x00;
   298 
   299 
   300         fOut = fopen(fileName.c_str(), "wb");
   301         if (!fOut)
   302         {
   303             fprintf(stderr,"Cannot create file: %s\n", fileName.c_str());
   304             return false;
   305         }
   306         fwrite(&bmpHeader, sizeof(BMPHEADER), 1, fOut);
   307         fwrite(&bmpColor1, sizeof(RGBQUAD), 1, fOut);
   308         fwrite(&bmpColor2, sizeof(RGBQUAD), 1, fOut);
   309 
   310         for (y=bitmap->Height(); y>0; y--)
   311         {
   312             pByte = (char*)bmpdata + (y-1)*((bitmap->Width()+7)/8);
   313             iWrote = 0;
   314             for (x=0; x<(uint32_t) bitmap->Width()/8; x++)
   315             {
   316                 *pByte = *pByte^0xff;
   317                 if (fwrite(pByte, sizeof(char), 1, fOut)!=1)
   318                 {
   319                     fclose(fOut);
   320                     return false;
   321                 }
   322                 iWrote++;
   323                 pByte++;
   324             }
   325             // Scan line must be 4-byte-alligned
   326             while (iWrote%4)
   327             {
   328                 if (fwrite(&Dummy, sizeof(char), 1, fOut)!=1)
   329                 {
   330                     fclose(fOut);
   331                     return 3;
   332                 }
   333                 iWrote++;
   334             }
   335         }
   336         fclose(fOut);
   337     }
   338     return true;
   339 }
   340 
   341 bool cBMPFile::Save(GLCD::cImage & image, const std::string & fileName)
   342 {
   343     const GLCD::cBitmap * bitmap;
   344 
   345     if (image.Count() == 1)
   346     {
   347         bitmap = image.GetBitmap(0);
   348         if (bitmap)
   349         {
   350             if (!Save(bitmap, fileName))
   351             {
   352                 return false;
   353             }
   354         }
   355     }
   356     else
   357     {
   358         uint16_t i;
   359         char tmpStr[256];
   360 
   361         for (i = 0; i < image.Count(); i++)
   362         {
   363             sprintf(tmpStr, "%.248s.%05d", fileName.c_str(), i);
   364             bitmap = image.GetBitmap(i);
   365             if (bitmap)
   366             {
   367                 if (!Save(bitmap, tmpStr))
   368                 {
   369                     return false;
   370                 }
   371             }
   372         }
   373     }
   374     return true;
   375 }