SBSPSS/Utils/parkgrab/bmploader.cpp
2000-08-29 16:26:01 +00:00

670 lines
13 KiB
C++

/*=========================================================================
FILENAME.CPP
Author: Gary Liddon @
Created:
Project:
Purpose:
Copyright (c) 1998 G R Liddon
===========================================================================*/
/*----------------------------------------------------------------------
Includes
-------- */
/* Std Lib
------- */
/* Glib
---- */
#include <frame.hpp>
#include <misc.hpp>
/* Local
----- */
/*----------------------------------------------------------------------
Tyepdefs && Defines
------------------- */
/*----------------------------------------------------------------------
Structure defintions
-------------------- */
/*----------------------------------------------------------------------
Function Prototypes
------------------- */
using namespace std;
/*----------------------------------------------------------------------
Vars
---- */
/*----------------------------------------------------------------------
Data
---- */
struct RGB
{
u8 r,g,b;
};
class BITMAP
{
public:
BITMAP(void)
{
m_width=0;
m_height=0;
}
void setSize(int width,int height)
{
bitMap.resize(width*height);
m_width=width;
m_height=height;
}
void clear(void)
{
if (m_width && m_height)
memset(&bitMap[0],0,m_width*m_height);
}
void line(unsigned int y,unsigned int x,u8 pix)
{
if (x >= m_width)
{
GObject::Error(ERR_WARNING,"Out of X boundary - %d %d\n", x, m_width);
x = m_width-1;
}
if (y >= m_height)
{
GObject::Error(ERR_WARNING,"Out of Y boundary - %d %d\n", y, m_height);
y = m_height-1;
}
bitMap[y*m_width+x]=pix;
}
u8 const * getBitMap(void) const
{return(&bitMap[0]);}
protected:
int m_width;
int m_height;
vector<u8> bitMap;
};
/*----------------------------------------------------------------------
Function:
Purpose:
Params:
Returns:
---------------------------------------------------------------------- */
#include <stdlib.h>
#include <errno.h>
#include <string.h>
#include <limits.h>
#define BI_RGB 0
#define BI_RLE8 1
#define BI_RLE4 2
#define BI_BITFIELDS 3
#define OS2INFOHEADERSIZE 12
#define WININFOHEADERSIZE 40
typedef struct BITMAPFILEHEADER
{
unsigned long bfType;
unsigned long bfSize;
unsigned short bfReserved1;
unsigned short bfReserved2;
unsigned long bfOffBits;
} BITMAPFILEHEADER;
/* Used for both OS/2 and Windows BMP.
* Contains only the parameters needed to load the image
*/
typedef struct BITMAPINFOHEADER
{
unsigned long biWidth;
unsigned long biHeight;
unsigned short biBitCount;
unsigned long biCompression;
} BITMAPINFOHEADER;
typedef struct WINBMPINFOHEADER /* size: 40 */
{
unsigned long biWidth;
unsigned long biHeight;
unsigned short biPlanes;
unsigned short biBitCount;
unsigned long biCompression;
unsigned long biSizeImage;
unsigned long biXPelsPerMeter;
unsigned long biYPelsPerMeter;
unsigned long biClrUsed;
unsigned long biClrImportant;
} WINBMPINFOHEADER;
typedef struct OS2BMPINFOHEADER /* size: 12 */
{
unsigned short biWidth;
unsigned short biHeight;
unsigned short biPlanes;
unsigned short biBitCount;
} OS2BMPINFOHEADER;
/* read_bmfileheader:
* Reads a BMP file header and check that it has the BMP magic number.
*/
static int read_bmfileheader(Gifstream & f, BITMAPFILEHEADER *fileheader)
{
fileheader->bfType = f.Get16();
fileheader->bfSize= f.Get32();
fileheader->bfReserved1= f.Get16();
fileheader->bfReserved2= f.Get16();
fileheader->bfOffBits= f.Get32();
if (fileheader->bfType != 19778)
return -1;
return 0;
}
/* read_win_bminfoheader:
* Reads information from a BMP file header.
*/
static int read_win_bminfoheader(Gifstream & f, BITMAPINFOHEADER *infoheader)
{
WINBMPINFOHEADER win_infoheader;
win_infoheader.biWidth = f.Get32();
win_infoheader.biHeight = f.Get32();
win_infoheader.biPlanes = f.Get16();
win_infoheader.biBitCount = f.Get16();
win_infoheader.biCompression = f.Get32();
win_infoheader.biSizeImage = f.Get32();
win_infoheader.biXPelsPerMeter = f.Get32();
win_infoheader.biYPelsPerMeter = f.Get32();
win_infoheader.biClrUsed = f.Get32();
win_infoheader.biClrImportant = f.Get32();
infoheader->biWidth = win_infoheader.biWidth;
infoheader->biHeight = win_infoheader.biHeight;
infoheader->biBitCount = win_infoheader.biBitCount;
infoheader->biCompression = win_infoheader.biCompression;
return 0;
}
/* read_os2_bminfoheader:
* Reads information from an OS/2 format BMP file header.
*/
static int read_os2_bminfoheader(Gifstream & f, BITMAPINFOHEADER *infoheader)
{
OS2BMPINFOHEADER os2_infoheader;
os2_infoheader.biWidth = f.Get16();
os2_infoheader.biHeight = f.Get32();
os2_infoheader.biPlanes = f.Get32();
os2_infoheader.biBitCount = f.Get32();
infoheader->biWidth = os2_infoheader.biWidth;
infoheader->biHeight = os2_infoheader.biHeight;
infoheader->biBitCount = os2_infoheader.biBitCount;
infoheader->biCompression = 0;
return 0;
}
/* read_bmicolors:
* Loads the color pallete for 1,4,8 bit formats.
*/
static void read_bmicolors(int ncols, RGB *pal, Gifstream & f,int win_flag)
{
int i;
for (i=0; i<ncols; i++)
{
pal[i].b = f.get();
pal[i].g = f.get();
pal[i].r = f.get();
if (win_flag)
f.get();
}
}
/* read_1bit_line:
* Support function for reading the 1 bit bitmap file format.
*/
static void read_1bit_line(int length, Gifstream & f, BITMAP *bmp, int line)
{
unsigned char b[32];
unsigned long n;
int i, j, k;
int pix;
for (i=0; i<length; i++)
{
j = i % 32;
if (j == 0)
{
n = f.Get32();
for (k=0; k<32; k++)
{
b[31-k] = n & 1;
n = n >> 1;
}
}
pix = b[j];
bmp->line(line,i,pix);
}
}
/* read_4bit_line:
* Support function for reading the 4 bit bitmap file format.
*/
static void read_4bit_line(int length, Gifstream & f, BITMAP *bmp, int line)
{
unsigned char b[8];
unsigned long n;
int i, j, k;
int temp;
int pix;
for (i=0; i<length; i++)
{
j = i % 8;
if (j == 0)
{
n = f.Get32();
for (k=0; k<4; k++)
{
temp = n & 255;
b[k*2+1] = temp & 15;
temp = temp >> 4;
b[k*2] = temp & 15;
n = n >> 8;
}
}
pix = b[j];
bmp->line(line,i,pix);
}
}
/* read_8bit_line:
* Support function for reading the 8 bit bitmap file format.
*/
static void read_8bit_line(int length, Gifstream & f, BITMAP *bmp, int line)
{
unsigned char b[4];
unsigned long n;
int i, j, k;
int pix;
for (i=0; i<length; i++)
{
j = i % 4;
if (j == 0)
{
n = f.Get32();
for (k=0; k<4; k++)
{
b[k] = n & 255;
n = n >> 8;
}
}
pix = b[j];
bmp->line(line,i,pix);
}
}
/* read_24bit_line:
* Support function for reading the 24 bit bitmap file format, doing
* our best to convert it down to a 256 color pallete.
*/
static void read_24bit_line(int length, Gifstream & f, BITMAP *bmp, int line)
{
#if 0
int i, nbytes;
RGB c;
nbytes=0;
for (i=0; i<length; i++) {
c.b = f.get();
c.g = f.get();
c.r = f.get();
bmp->line[line][i*3+_rgb_r_shift_24/8] = c.r;
bmp->line[line][i*3+_rgb_g_shift_24/8] = c.g;
bmp->line[line][i*3+_rgb_b_shift_24/8] = c.b;
nbytes += 3;
}
nbytes = nbytes % 4;
if (nbytes != 0)
for (i=nbytes; i<4; i++)
f.get();;
#endif
}
/* read_image:
* For reading the noncompressed BMP image format.
*/
static void read_image(Gifstream & f, BITMAP *bmp, BITMAPINFOHEADER *infoheader)
{
int i, line;
for (i=0; i<(int)infoheader->biHeight; i++) {
line = i;
switch (infoheader->biBitCount) {
case 1:
read_1bit_line(infoheader->biWidth, f, bmp, infoheader->biHeight-i-1);
break;
case 4:
read_4bit_line(infoheader->biWidth, f, bmp, infoheader->biHeight-i-1);
break;
case 8:
read_8bit_line(infoheader->biWidth, f, bmp, infoheader->biHeight-i-1);
break;
case 24:
read_24bit_line(infoheader->biWidth, f, bmp, infoheader->biHeight-i-1);
break;
}
}
}
/* read_RLE8_compressed_image:
* For reading the 8 bit RLE compressed BMP image format.
*/
static void read_RLE8_compressed_image(Gifstream & f, BITMAP *bmp, BITMAPINFOHEADER *infoheader)
{
unsigned char count, val, val0;
int j, pos, line;
int eolflag, eopicflag;
eopicflag = 0;
line = infoheader->biHeight - 1;
while (eopicflag == 0) {
pos = 0; /* x position in bitmap */
eolflag = 0; /* end of line flag */
while ((eolflag == 0) && (eopicflag == 0)) {
count = f.get();
val = f.get();
if (count > 0) { /* repeat pixel count times */
for (j=0;j<count;j++) {
bmp->line(line,pos,val);
pos++;
}
}
else {
switch (val) {
case 0: /* end of line flag */
eolflag=1;
break;
case 1: /* end of picture flag */
eopicflag=1;
break;
case 2: /* displace picture */
count = f.get();
val = f.get();
pos += count;
line -= val;
break;
default: /* read in absolute mode */
for (j=0; j<val; j++) {
val0 = f.get();
bmp->line(line,pos,val0);
pos++;
}
if (j%2 == 1)
val0 = f.get(); /* align on word boundary */
break;
}
}
if (pos > (int)infoheader->biWidth)
eolflag=1;
}
line--;
if (line < 0)
eopicflag = 1;
}
}
/* read_RLE4_compressed_image:
* For reading the 4 bit RLE compressed BMP image format.
*/
static void read_RLE4_compressed_image(Gifstream & f, BITMAP *bmp, BITMAPINFOHEADER *infoheader)
{
unsigned char b[8];
unsigned char count;
unsigned short val0, val;
int j, k, pos, line;
int eolflag, eopicflag;
eopicflag = 0; /* end of picture flag */
line = infoheader->biHeight - 1;
while (eopicflag == 0) {
pos = 0;
eolflag = 0; /* end of line flag */
while ((eolflag == 0) && (eopicflag == 0)) {
count = f.get();
val = f.get();
if (count > 0) { /* repeat pixels count times */
b[1] = val & 15;
b[0] = (val >> 4) & 15;
for (j=0; j<count; j++) {
bmp->line(line,pos,b[j%2]);
pos++;
}
}
else {
switch (val) {
case 0: /* end of line */
eolflag=1;
break;
case 1: /* end of picture */
eopicflag=1;
break;
case 2: /* displace image */
count = f.get();
val = f.get();
pos += count;
line -= val;
break;
default: /* read in absolute mode */
for (j=0; j<val; j++) {
if ((j%4) == 0) {
val0 = f.Get16();
for (k=0; k<2; k++) {
b[2*k+1] = val0 & 15;
val0 = val0 >> 4;
b[2*k] = val0 & 15;
val0 = val0 >> 4;
}
}
bmp->line(line,pos,b[j%4]);
pos++;
}
break;
}
}
if (pos > (int)infoheader->biWidth)
eolflag=1;
}
line--;
if (line < 0)
eopicflag = 1;
}
}
/* load_bmp:
* Loads a Windows BMP file, returning a bitmap structure and storing
* the pallete data in the specified pallete (this should be an array of
* at least 256 RGB structures).
*
* Thanks to Seymour Shlien for contributing this function.
*/
void load_bmp(Frame & frm,char const *filename)
{
BITMAPFILEHEADER fileheader;
BITMAPINFOHEADER infoheader;
RGB pal[256];
BITMAP bmp;
Gifstream f(Gifstream::LITTLE_ENDIAN);
int ncol;
unsigned long biSize;
f.open(filename,ios::in|ios::binary);
if (!f)
GObject::Error(ERR_FATAL,"couldn't open file %s",filename);
if (read_bmfileheader(f, &fileheader) != 0)
{
GObject::Error(ERR_FATAL,"error reading bmp hdr for %s",filename);
}
biSize = f.Get32();
if (biSize == WININFOHEADERSIZE)
{
if (read_win_bminfoheader(f, &infoheader) != 0)
GObject::Error(ERR_FATAL,"error reading windows bmp info hdr for %s",filename);
/* compute number of colors recorded */
ncol = (fileheader.bfOffBits - 54) / 4;
read_bmicolors(ncol, pal, f, 1);
}
else if (biSize == OS2INFOHEADERSIZE)
{
if (read_os2_bminfoheader(f, &infoheader) != 0)
GObject::Error(ERR_FATAL,"error reading os2 bmp info hdr for %s",filename);
/* compute number of colors recorded */
ncol = (fileheader.bfOffBits - 26) / 3;
read_bmicolors(ncol, pal, f, 0);
}
else
{
GObject::Error(ERR_FATAL,"error finding correct hdr for bmp %s",filename);
}
if (infoheader.biBitCount != 4 && infoheader.biBitCount != 8)
GObject::Error(ERR_FATAL,"only handles 4 && 8 bit bmps not %d : %s",infoheader.biBitCount,filename);
bmp.setSize(infoheader.biWidth, infoheader.biHeight);
bmp.clear();
switch (infoheader.biCompression)
{
case BI_RGB:
read_image(f, &bmp, &infoheader);
break;
case BI_RLE8:
read_RLE8_compressed_image(f, &bmp, &infoheader);
break;
case BI_RLE4:
read_RLE4_compressed_image(f, &bmp, &infoheader);
break;
default:
GObject::Error(ERR_FATAL,"unknown compression foramt for %s",filename);
break;
}
f.close();
{
Palette palObj;
for (int f=0;f<ncol;f++)
{
Colour & col = palObj[f];
col.SetRGB(pal[f].r,pal[f].g,pal[f].b);
}
frm.SetFrame(bmp.getBitMap(),infoheader.biWidth,infoheader.biHeight,palObj);
}
}
/*===========================================================================
end */