/*========================================================================= FRAME.CPP Author: Gary Liddon @ Fareham Created: Project: Purpose: Copyright (c) 1997 G R Liddon ===========================================================================*/ /*---------------------------------------------------------------------- Includes -------- */ /* Std Lib ------- */ #include <conio.h> #include <math.h> /* STL --- */ //#include <alogrithm> #include <ALGORITHM> /* Glib ---- */ /* Local ----- */ #include "frame.hpp" #include "ilbm.hpp" #include "gutils.h" #include "misc.hpp" using namespace std; static void load_bmp(Frame & frm,char const *filename); /*---------------------------------------------------------------------- Function: Frame::Frame(void) ---------------------------------------------------------------------- */ Frame::Frame(void) { InitFrame(); } /*---------------------------------------------------------------------- Function: Copy Constructor ---------------------------------------------------------------------- */ Frame::Frame(Frame const & Fr) { InitFrame(); CopyFrame(Fr); } /*---------------------------------------------------------------------- Function: Destructor ---------------------------------------------------------------------- */ Frame::~Frame(void) { if (Buffa) delete Buffa; } /*---------------------------------------------------------------------- Function: Init the Frame ---------------------------------------------------------------------- */ void Frame::InitFrame(void) { Buffa=NULL; X=0; Y=0; } /*---------------------------------------------------------------------- Function: Purpose: Params: Returns: ---------------------------------------------------------------------- */ void Frame::CopyFrame(Frame const & Fr) { DumpStuff(); Width=Fr.Width; Height=Fr.Height; if (Fr.Buffa) { if (!(Buffa=new u8[Width*Height])) Error(ERM_OUTOFMEM); memcpy(Buffa,Fr.Buffa,Width*Height); } else Buffa=NULL; Name=Fr.Name; MyPal=Fr.MyPal; X=Fr.X; Y=Fr.Y; } /*---------------------------------------------------------------------- Function: Purpose: Params: Returns: ---------------------------------------------------------------------- */ void Frame::DumpStuff(void) { if (Buffa) delete Buffa; Width=0; Height=0; X=0; Y=0; } /*---------------------------------------------------------------------- Function: Purpose: Params: Returns: ---------------------------------------------------------------------- */ bool Frame::IsBlank(u8 BlankVal) { if (Buffa) { for (int f=0;f<Width*Height;f++) { if (Buffa[f] != BlankVal) return(false); } } return(true); } /*---------------------------------------------------------------------- Function: Purpose: Params: Returns: ---------------------------------------------------------------------- */ bool Frame::Grab(Frame const & Fr,Rect const & RetRect) { Rect GrabRect(RetRect); Rect FromRect=Fr; FromRect.X=0; FromRect.Y=0; FromRect.ClipRect(GrabRect); if (GrabRect) { InitFrame(); u8 const * GrAddr=&Fr.Buffa[GrabRect.Y*Fr.Width+GrabRect.X]; if (Buffa=new u8[GrabRect.W*GrabRect.H]) { Width=GrabRect.W; Height=GrabRect.H; MyPal=Fr.MyPal; for (int y=0;y<Height;y++) memcpy(&Buffa[y*Width],&GrAddr[y*Fr.Width],Width); } else Error(ERM_OUTOFMEM); return(true); } return(false); } /*---------------------------------------------------------------------- Function: Purpose: Params: Returns: ---------------------------------------------------------------------- */ bool Frame::DrawBox(Rect const & RetRect,u8 Col) { Rect GrabRect(RetRect); Rect FromRect=*this; FromRect.X=0; FromRect.Y=0; FromRect.ClipRect(GrabRect); if (GrabRect) { u8 * GrAddr=&Buffa[GrabRect.Y*Width+GrabRect.X]; for (int y=0;y<Height;y++) memset(&GrAddr[y*Width],Col,Width); return(true); } return(false); } /*---------------------------------------------------------------------- Function: Purpose: Params: Returns: ---------------------------------------------------------------------- */ void Frame::SetFrame(u8 const * nBuffa,int W,int H,Palette const & NewPal) { DumpStuff(); Width=W; Height=H; MyPal=NewPal; if (!(Buffa=new u8[Width*Height])) Error(ERM_OUTOFMEM); memcpy(Buffa,nBuffa,Width*Height); } /*---------------------------------------------------------------------- Function: Purpose: Params: Returns: ---------------------------------------------------------------------- */ void Frame::ReduceSinglePixels(int Threshold) { UINT cury,curx,col,lastcol,nextcol; UINT r,g,b,lastr,lastg,lastb,nextr,nextg,nextb,dist1,dist2; UCHAR * p; UINT RDLBM256_sy=Height; UINT RDLBM256_sx=Width; u8 * inbuf=Buffa; for(cury=0;cury<RDLBM256_sy;cury++) { p = inbuf+(cury*RDLBM256_sx); for(curx=0;curx<RDLBM256_sx;curx++) { col = *p; nextcol = *(p+1); if(curx && curx!=RDLBM256_sx-1 && col && col != lastcol && col != nextcol) { Colour * C; Colour * LC; Colour * NC; C=&MyPal[col]; LC=&MyPal[lastcol]; NC=&MyPal[nextcol]; r = C->GetR(); g = C->GetG();; b = C->GetB();; lastr = LC->GetR(); lastg = LC->GetG(); lastb = LC->GetB(); nextr = NC->GetR(); nextg = NC->GetG(); nextb = NC->GetB(); dist1 = ((lastr-r)*(lastr-r)) + ((lastg-g)*(lastg-g)) + ((lastb-b)*(lastb-b)); dist2 = ((nextr-r)*(nextr-r)) + ((nextg-g)*(nextg-g)) + ((nextb-b)*(nextb-b)); if(dist1 < dist2) { if(dist1 <= Threshold) { *p = lastcol; } } else { if(dist2 <= Threshold) *p = nextcol; } } lastcol = *p++; } } } /*---------------------------------------------------------------------- Function: Purpose: Params: Returns: ---------------------------------------------------------------------- */ void Frame::ReduceSize(void) { Rect MRect=FindBoundingRect(); Crop(MRect); } /*---------------------------------------------------------------------- Function: Purpose: Params: Returns: ---------------------------------------------------------------------- */ void Frame::Crop(Rect const & NewRect) { if (Buffa && NewRect) { Rect CopyRect; CopyRect=*this; CopyRect.X=0; CopyRect.Y=0; Rect MyRect=NewRect; CopyRect.ClipRect(MyRect); CopyRect=MyRect; if (CopyRect) { u8 * DestBuffa; if (!(DestBuffa=new u8[NewRect.Area()])) Error(ERM_OUTOFMEM); memset(DestBuffa,0,NewRect.Area()); u8 * Src=&Buffa[CopyRect.X+CopyRect.Y*Width]; u8 * Dst=DestBuffa; for (int yy=0;yy<CopyRect.H;yy++) { memcpy(Dst,Src,CopyRect.W); Src+=Width; Dst+=NewRect.W; } delete Buffa; Buffa=DestBuffa; Width=NewRect.W; Height=NewRect.H; } } } /*---------------------------------------------------------------------- Function: Purpose: Resize this image to another size (uses point sampling) Params: Returns: ---------------------------------------------------------------------- */ void Frame::Resize(int NewWidth,int NewHeight) { if (NewHeight != Height || NewWidth != Width) { vector<u8> NewPic; NewPic.resize(NewWidth*NewHeight); for (int y=0;y<NewHeight;y++) for (int x=0;x<NewWidth;x++) { float XFrac=float(x)/float(NewWidth); float YFrac=float(y)/float(NewHeight); int FromX=float(Width)*XFrac; int FromY=float(Height)*YFrac; NewPic[y*NewWidth+x]=Buffa[FromY*Width+FromX]; } DumpStuff(); Width=NewWidth; Height=NewHeight; if(!(Buffa=new u8[Width*Height])) Error(ERM_OUTOFMEM); memcpy(Buffa,&NewPic[0],Width*Height); } } /*---------------------------------------------------------------------- Function: Purpose: Params: Returns: ---------------------------------------------------------------------- */ Rect Frame::FindBoundingRect(void) { Rect RetRect; u8 * Bmap; Bmap=Buffa; if (Bmap) { int Bottom; int x,y; Bottom=-1; for (y=Height-1;y>=0 && Bottom==-1;y--) { for (x=0;x<Width && Bottom==-1;x++) if (Bmap[y*Width+x]) Bottom=y; } if (Bottom != -1) { int Top=-1; for (y=0;y<=Bottom && Top==-1;y++) { for (x=0;x<Width && Top==-1;x++) if (Bmap[y*Width+x]) Top=y; } if (Top != -1) { int Left=-1; for (x=0;x<Width && Left==-1;x++) { for (y=Top;y<=Bottom && Left==-1;y++) if (Bmap[y*Width+x]) Left=x; } if (Left!=-1) { int Right=-1; for (x=Width-1;x>=Left && Right==-1;x--) { for (y=Top;y<=Bottom && Right==-1;y++) if (Bmap[y*Width+x]) Right=x; } if (Right !=-1) { RetRect.X=Left; RetRect.Y=Top; RetRect.W=Right-Left+1; RetRect.H=Bottom-Top+1; } else Error(ERR_FATAL,"Strange frame"); } else Error(ERR_FATAL,"Strange frame"); } else Error(ERR_FATAL,"Strange frame"); } } return(RetRect); } /*---------------------------------------------------------------------- Function: Purpose: Params: Returns: ---------------------------------------------------------------------- */ void Frame::SaveLbm(char const * Lbm) { u8 * Pal; Pal=MyPal.MakeDpPal(); nilbm::SavePbm((char *)Lbm,Pal,Buffa,Width,Height); delete Pal; } /*---------------------------------------------------------------------- Function: Purpose: Params: Returns: ---------------------------------------------------------------------- */ void Frame::LoadLbm(char const * Lbm) { nilbm MyLbm(Lbm); if (!MyLbm.error()) { if (Buffa) delete Buffa; u8 const * CMap; Buffa=MyLbm.TakeBmap(); CMap=MyLbm.SeeCmap(); Width=MyLbm.GetWidth(); Height=MyLbm.GetHeight(); int NumOfCols=1<<MyLbm.GetPlanes(); for (int f=0;f<NumOfCols;f++) { MyPal[f].SetR(CMap[f*3+0]); MyPal[f].SetG(CMap[f*3+1]); MyPal[f].SetB(CMap[f*3+2]); } } else Error(ERR_FATAL,"Can't load lbm %s",Lbm); } /*---------------------------------------------------------------------- Function: Purpose: Load a paletted BMP file Params: Returns: ---------------------------------------------------------------------- */ void Frame::LoadBMP(char const * FileName) { load_bmp(*this,FileName); } /*---------------------------------------------------------------------- Function: Purpose: Params: Returns: ---------------------------------------------------------------------- */ int Frame::GetNumOfCols(void) const { int Ret; Ret=0; if (Buffa) { for (int f=0;f<Width*Height;f++) { if (Buffa[f] > Ret) Ret=Buffa[f]; } } return(Ret+1); } /*---------------------------------------------------------------------- Function: Purpose: Params: Returns: ---------------------------------------------------------------------- */ void Frame::FlipX(void) { if (Buffa && Width && Height) { vector<u8> Buffa2; Buffa2.resize(Width*Height); for (int y=0;y<Height;y++) { for (int x=0;x<Width;x++) Buffa2[((Width-1)-x)+y*Width]=Buffa[x+y*Width]; } memcpy(Buffa,&Buffa2[0],Width*Height); } } /*---------------------------------------------------------------------- Function: Purpose: Params: Returns: ---------------------------------------------------------------------- */ void Frame::FlipY(void) { if (Buffa && Width && Height) { vector<u8> Buffa2; Buffa2.resize(Width*Height); for (int y=0;y<Height;y++) memcpy(&Buffa2[((Height-1)-y)*Width],&Buffa[y*Width],Width); memcpy(Buffa,&Buffa2[0],Width*Height); } } /*---------------------------------------------------------------------- Function: Purpose: Params: Returns: ---------------------------------------------------------------------- */ void Frame::Remap(Palette const & P) { if (Buffa) { int * RemapBuffer; RemapBuffer=P.MakeRemapTable(MyPal); for (int f=0;f<Width*Height;f++) Buffa[f]=RemapBuffer[Buffa[f]]; MyPal=P; delete RemapBuffer; } } /*---------------------------------------------------------------------- Function: Purpose: Params: Returns: ---------------------------------------------------------------------- */ void Frame::MakeRGBA(u8 * Dest,bool ZeroIsTrans) { if (Buffa) { int Area; Area=Width*Height; for (int f=0;f<Area;f++) { Dest[f*4+0]=MyPal[Buffa[f]].GetR(); Dest[f*4+1]=MyPal[Buffa[f]].GetG(); Dest[f*4+2]=MyPal[Buffa[f]].GetB(); if (ZeroIsTrans) Dest[f*4+3]=Buffa[f] ? 255 : 0; else Dest[f*4+3]=255; } } } /*---------------------------------------------------------------------- Function: Purpose: Params: Returns: ---------------------------------------------------------------------- */ void Frame::MakeRGB(u8 * Dest) { if (Buffa) { int Area; Area=Width*Height; for (int f=0;f<Area;f++) { Dest[f*3+0]=MyPal[Buffa[f]].GetR(); Dest[f*3+1]=MyPal[Buffa[f]].GetG(); Dest[f*3+2]=MyPal[Buffa[f]].GetB(); } } } /*---------------------------------------------------------------------- Function: Purpose: Params: Returns: ---------------------------------------------------------------------- */ void Frame::Plot(Frame & Dest,int X,int Y) { if (Buffa && Dest.Buffa) { Rect DestRect=Dest; Rect NewR(X,Y,Width,Height); DestRect.X=0; DestRect.Y=0; DestRect.ClipRect(NewR); if (NewR) { int NumOfCols=MyPal.GetNumOfCols(); int * RemapBuffer; int XIndent=NewR.X-X; int YIndent=NewR.Y-Y; u8 * PicSrc=&Buffa[XIndent+YIndent*Width]; RemapBuffer=Dest.MyPal.MakeRemapTable(MyPal); for (int yy=NewR.Y;yy<NewR.Y+NewR.H;yy++) { for (int xx=0;xx<NewR.W;xx++) Dest.Buffa[yy*Dest.Width+NewR.X+xx]=RemapBuffer[PicSrc[(yy-NewR.Y)*Width+xx]]; } delete RemapBuffer; } } } /*---------------------------------------------------------------------- Function: Purpose: Params: Returns: ---------------------------------------------------------------------- */ void Frame::PlotBox(Rect const & R,int Col) { Rect NewR(0,0,Width,Height); Rect DRect; DRect=R; NewR.ClipRect(DRect); if (DRect && Buffa) { for (int yy=DRect.Y;yy<DRect.Y+DRect.H;yy++) memset(&Buffa[yy*Width+DRect.X],Col,DRect.W); } } /*---------------------------------------------------------------------- Function: Purpose: Params: Returns: ---------------------------------------------------------------------- */ void Frame::PlotTrans(Frame & Dest,int X,int Y,int TrCol) { if (Buffa && Dest.Buffa) { Rect DestRect=Dest; Rect NewR(X,Y,Width,Height); DestRect.X=0; DestRect.Y=0; DestRect.ClipRect(NewR); if (NewR) { int NumOfCols=MyPal.GetNumOfCols(); int * RemapBuffer; int XIndent=NewR.X-X; int YIndent=NewR.Y-Y; u8 * PicSrc=&Buffa[XIndent+YIndent*Width]; RemapBuffer=Dest.MyPal.MakeRemapTable(MyPal); for (int yy=NewR.Y;yy<NewR.Y+NewR.H;yy++) { for (int xx=0;xx<NewR.W;xx++) { if (PicSrc[(yy-NewR.Y)*Width+xx] != TrCol) Dest.Buffa[yy*Dest.Width+NewR.X+xx]=RemapBuffer[PicSrc[(yy-NewR.Y)*Width+xx]]; } } delete RemapBuffer; } } } void Frame::ReplaceColour(int ColNum,int RepNum) { if (Buffa && Width && Height) { if ((ColNum<MyPal.GetNumOfCols()) && (RepNum<MyPal.GetNumOfCols())) { for (int f=0;f<Width*Height;f++) { if (Buffa[f]==ColNum) Buffa[f]=RepNum; } } } } /*---------------------------------------------------------------------- Function: Purpose: Params: Returns: ---------------------------------------------------------------------- */ void Frame::ReducePal(void) { if (Buffa && Width && Height) MyPal.SetPalSize(GetNumOfCols()); } /*---------------------------------------------------------------------- Function: Purpose: Params: Returns: ---------------------------------------------------------------------- */ void Frame::Clear(int Col) { if (Buffa && Width && Height) memset(Buffa,Col,Width*Height); } /*---------------------------------------------------------------------- Function: Purpose: Params: Returns: ---------------------------------------------------------------------- */ struct ColPair { Colour C; int Uses; bool operator==(ColPair const &Col) const {return(Uses==Col.Uses);} bool operator<(ColPair const &Col) const {return(Uses<Col.Uses);} }; class PredicateColPair { public: bool operator()(ColPair const & R1,ColPair const & R2) const { return (R2.Uses<R1.Uses); } }; void Frame::ReduceColours(int TargColours) { if (Buffa && TargColours <=255) { Palette NewPal; for (int f=0;f<TargColours;f++) NewPal[f].SetRGB(0xff,0,0xff); vector<ColPair> Colours; Colours.resize(256); for (f=0;f<256;f++) Colours[f].Uses=0; for (f=0;f<Width*Height;f++) { if (Buffa[f]) { Colours[Buffa[f]].C=MyPal[Buffa[f]]; Colours[Buffa[f]].Uses++; } } sort(Colours.begin(),Colours.end()); for (f=63;f>0;f--) { int ColIndex=255-63+f; if (Colours[ColIndex].Uses) NewPal[f]=Colours[ColIndex].C; } Remap(NewPal); } } /*---------------------------------------------------------------------- Function: Purpose: Params: Returns: ---------------------------------------------------------------------- */ void Frame::AddPixelSurround(int Col) { if (Buffa && Col < MyPal.GetNumOfCols()) { Frame NewFrame; NewFrame=*this; NewFrame.Width+=2; NewFrame.Height+=2; NewFrame.DumpStuff(); if(!(NewFrame.Buffa=new u8[NewFrame.Width*NewFrame.Height])) Error(ERM_OUTOFMEM); memset(NewFrame.Buffa,0,NewFrame.Width*NewFrame.Height); PlotTrans(NewFrame,0,0); PlotTrans(NewFrame,0,1); PlotTrans(NewFrame,0,2); PlotTrans(NewFrame,1,0); PlotTrans(NewFrame,1,2); PlotTrans(NewFrame,2,0); PlotTrans(NewFrame,2,1); PlotTrans(NewFrame,2,2); for (int f=0;f<NewFrame.Width*NewFrame.Height;f++) { if (NewFrame.Buffa[f]) NewFrame.Buffa[f]=Col; } PlotTrans(NewFrame,1,1); *this=NewFrame; } } /*---------------------------------------------------------------------- Function: Purpose: Params: Returns: ---------------------------------------------------------------------- */ void Frame::Expand(int BorderWidth,bool DupeEdges) { Frame NewFrame; NewFrame=*this; NewFrame.Width+=BorderWidth*2; NewFrame.Height+=BorderWidth*2; if(!(NewFrame.Buffa=new u8[NewFrame.Width*NewFrame.Height])) Error(ERM_OUTOFMEM); memset(NewFrame.Buffa,0,NewFrame.Width*NewFrame.Height); if (DupeEdges) { for (int f=0;f<BorderWidth*2+1;f++) Plot(NewFrame,f,BorderWidth); for (f=0;f<BorderWidth*2+1;f++) Plot(NewFrame,BorderWidth,f); } Plot(NewFrame,BorderWidth,BorderWidth); *this=NewFrame; } /*---------------------------------------------------------------------- Function: Purpose: Params: Returns: ---------------------------------------------------------------------- */ Rect::Rect(void) { X=0; Y=0; W=0; H=0; } /*---------------------------------------------------------------------- Function: Purpose: Params: Returns: ---------------------------------------------------------------------- */ ostream & operator<<(ostream & str,Rect const & Fr) { str<<"X,Y = ("<<Fr.X<<","<<Fr.Y<<") WH=("<<Fr.W<<","<<Fr.H<<")"; return(str); } /*---------------------------------------------------------------------- Function: Purpose: Params: Returns: ---------------------------------------------------------------------- */ void Rect::ClipRect(Rect & RectToClip) const { if (IsColiding(RectToClip)) { if (RectToClip.X < X) { RectToClip.W-=X-RectToClip.X; RectToClip.X=X; } if (RectToClip.Y < Y) { RectToClip.H-=Y-RectToClip.Y; RectToClip.Y=Y; } if ((RectToClip.X+RectToClip.W) > (X+W)) RectToClip.W-=(RectToClip.X+RectToClip.W)-(X+W); if ((RectToClip.Y+RectToClip.H) > (Y+H)) RectToClip.H-=(RectToClip.Y+RectToClip.H)-(Y+H); } else { RectToClip.W=0; RectToClip.H=0; RectToClip.X=0; RectToClip.Y=0; } } /*---------------------------------------------------------------------- Function: Purpose: Params: Returns: ---------------------------------------------------------------------- */ bool Rect::IsColiding(Rect const & NewRect) const { if ((NewRect.X+NewRect.W) <= X) return(false); if ((X+W) <= NewRect.X) return(false); if ((NewRect.Y+NewRect.H) <= Y) return(false); if ((Y+H) <= NewRect.Y) return(false); return(true); } 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 || y >= m_height) GObject::Error(ERR_FATAL,"out of bounds"); else 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. */ static 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 */