?? winimage.cpp
字號:
// ****************************************************************************
//
// WINIMAGE.CPP : Generic classes for raster images (MSWindows specialization)
//
// Content: Member definitions for:
// - class C_Image : Storage class for single images
// - class C_ImageSet : Storage class for sets of images
// - class C_AnimationWindow : Window Class to display animations
//
// (Includes routines to Load and Save BMP files and to load GIF files into
// these classes).
//
// --------------------------------------------------------------------------
//
// Copyright ?2000, Juan Soulie <jsoulie@cplusplus.com>
//
// Permission to use, copy, modify, distribute and sell this software or any
// part thereof and/or its documentation for any purpose is granted without fee
// provided that the above copyright notice and this permission notice appear
// in all copies.
//
// This software is provided "as is" without express or implied warranty of
// any kind. The author shall have no liability with respect to the
// infringement of copyrights or patents that any modification to the content
// of this file or this file itself may incur.
//
// ****************************************************************************
#include "stdafx.h"
#include <windows.h>
#include <fstream>
#include "winimage.h"
using namespace std;
// Error processing macro (NO-OP by default):
#define ERRORMSG(PARAM) {}
// ****************************************************************************
// * C_Image Member definitions *
// ****************************************************************************
C_ImageSet::~C_ImageSet(){
for (int n=0;n<nImages;n++) delete img[n]; delete[] img;
}
void C_ImageSet::Reset()
{
for (int n=0;n<nImages;n++)
delete img[n];
delete[] img;
img=0;
nImages=0;
nLoops=0;
}
// Init: Allocates space for raster and palette in GDI-compatible structures.
void C_Image::Init(int iWidth, int iHeight, int iBPP) {
if (Raster) {delete[]Raster;Raster=0;}
if (pbmi) {delete[]pbmi;pbmi=0;}
// Standard members setup
Transparent=-1;
BytesPerRow = Width = iWidth; Height=iHeight; BPP=iBPP;
// Animation Extra members setup:
xPos=xPos=Delay=0;
if (BPP==24)
{BytesPerRow*=3; pbmi=(BITMAPINFO*)new char [sizeof(BITMAPINFO)];}
else
{
pbmi=(BITMAPINFO*)
new char[sizeof(BITMAPINFOHEADER)+(1<<BPP)*sizeof(COLOR)];
Palette=(COLOR*)((char*)pbmi+sizeof(BITMAPINFOHEADER));
}
BytesPerRow += (ALIGN-Width%ALIGN) % ALIGN; // Align BytesPerRow
Raster = new char [BytesPerRow*Height];
pbmi->bmiHeader.biSize=sizeof (BITMAPINFOHEADER);
pbmi->bmiHeader.biWidth=Width;
pbmi->bmiHeader.biHeight=-Height; // negative means up-to-bottom
pbmi->bmiHeader.biPlanes=1;
pbmi->bmiHeader.biBitCount=(BPP<8?8:BPP); // Our raster is byte-aligned
pbmi->bmiHeader.biCompression=BI_RGB;
pbmi->bmiHeader.biSizeImage=0;
pbmi->bmiHeader.biXPelsPerMeter=11811;
pbmi->bmiHeader.biYPelsPerMeter=11811;
pbmi->bmiHeader.biClrUsed=0;
pbmi->bmiHeader.biClrImportant=0;
}
// GDIPaint: Paint the raster image onto a DC
int C_Image::GDIPaint (HDC hdc,int x, int y,int iWidth,int iHeight)
{
return SetDIBitsToDevice (hdc,x,y,iWidth,iHeight,0,0,
0,Height,(LPVOID)Raster,pbmi,0);
}
// operator=: copies an object's content to another
C_Image& C_Image::operator = (C_Image& rhs)
{
Init(rhs.Width,rhs.Height,rhs.BPP); // respects virtualization
memcpy (Raster,rhs.Raster,BytesPerRow*Height);
memcpy ((char*)Palette,(char*)rhs.Palette,(1<<BPP)*sizeof(*Palette));
return *this;
}
// ****************************************************************************
// * C_ImageSet Member definitions *
// ****************************************************************************
// AddImage: Adds an image object to the back of the img vector.
void C_ImageSet::AddImage (C_Image* newimage)
{
C_Image ** pTempImg = new C_Image* [nImages+1];
int n = 0;
for (n=0;n<nImages;n++) pTempImg[n]=img[n]; // (pointer copy)
delete[] img;
img=pTempImg;
img[n]=newimage;
nImages++;
}
// ****************************************************************************
// * FILE FORMAT SUPPORT ROUTINES *
// ****************************************************************************
// ****************************************************************************
// * LoadBMP *
// * Load a BMP File into the C_Image object *
// * (c) Sept2000, Juan Soulie <jsoulie@cplusplus.com> *
// ****************************************************************************
int C_Image::LoadBMP (char* szFileName)
{
int n;
// Open file.
ifstream bmpfile (szFileName , ios::in | ios::binary | ios::_Nocreate);
if (! bmpfile.is_open()) { ERRORMSG("File not found"); return 0; }
// *1* LOAD BITMAP FILE HEADER
struct BITMAPFILEHEADER {
unsigned short bfType;
unsigned long bfSize;
unsigned short bfReserved1;
unsigned short bfReserved2;
unsigned long bfOffBits;
} bmfh;
bmpfile.read ((char*)&bmfh,sizeof (bmfh));
// Check filetype signature
if (bmfh.bfType!='MB') { ERRORMSG("Not a valid BMP File"); return 0; }
// *2* LOAD BITMAP INFO HEADER
struct BITMAPINFOHEADER {
unsigned long biSize;
long biWidth;
long biHeight;
unsigned short biPlanes;
unsigned short biBitCount;
unsigned long biCompression;
unsigned long biSizeImage;
long biXPelsPerMeter;
long biYPelsPerMeter;
unsigned long biClrUsed;
unsigned long biClrImportant;
} bmih;
bmpfile.read ((char*)&bmih,sizeof (bmih));
// Check for supported Color depths
if ((bmih.biBitCount!=1) &&
(bmih.biBitCount!=4) &&
(bmih.biBitCount!=8) &&
(bmih.biBitCount!=24))
{ ERRORMSG("Color depth not supported"); return 0; }
// Check if file is compressed
if (bmih.biCompression!=0)
{ ERRORMSG("File uses unsupported compression"); return 0; }
// Set: Allocate memory to contain Data
Init (bmih.biWidth,
(bmih.biHeight>0) ? bmih.biHeight: -bmih.biHeight, // abs
bmih.biBitCount);
// *3* IF BPP AREN'T 24, LOAD PALETTE.
if (BPP!=24)
{
for (n=0;n< 1<<BPP;n++)
{
Palette[n].b=bmpfile.get();
Palette[n].g=bmpfile.get();
Palette[n].r=bmpfile.get();
bmpfile.get(); // 4th byte of RGBQUAD discarded
}
}
// *4* LOAD RASTER DATA
// Seek Raster Data in file
bmpfile.seekg (bmfh.bfOffBits,ios::beg);
int PixelsPerByte = 8/BPP; //used only if BPP are less than 8
int BitMask = (1<<BPP)-1; //used only if BPP are less than 8
// Raster Data Rows are 32bit aligned in BMP files.
int RowAlignmentInFile = ((4- ((Width*BPP+7)/8)%4)%4); // (bytes)
for (int row=0; row<Height; row++)
{
char * pPixel;
// If height is positive the bmp is bottom-up, set adequate row info:
pPixel= Raster + BytesPerRow *
( (bmih.biHeight>0)? Height-row-1 : row );
if (BPP >= 8) // 8 or more BPP: Read as block.
bmpfile.read (pPixel, Width*BPP/8);
else // Less than 8BPP: Read and store byte aligned.
{
int charGot;
for (int col=0; col < Width; col+=PixelsPerByte)
{
charGot=bmpfile.get();
for (int bit=8 ; bit >0 ; bit -= BPP) // high to low
*pPixel++ = (charGot>> (bit - BPP)) & BitMask;
}
}
// Ignore aligment bytes of file:
for (int m=0; m<RowAlignmentInFile; m++) bmpfile.get ();
}
bmpfile.close();
return 1;
}
// ****************************************************************************
// * SaveBMP *
// * Save the content of a C_Image object into a BMP file *
// * (c) Sept2000, Juan Soulie <jsoulie@cplusplus.com> *
// ****************************************************************************
int C_Image::SaveBMP (char * szFileName)
{
int n;
// Create file.
ofstream bmpfile (szFileName , ios::out | ios::binary | ios::trunc);
if (! bmpfile.is_open()) { ERRORMSG("Error creating file"); return 0;}
// determine BPP for file:
int SaveBPP;
if (BPP == 1) SaveBPP=1;
else if (BPP <= 4) SaveBPP=4;
else if (BPP <= 8) SaveBPP=8;
else SaveBPP=24;
// *1* SAVE BITMAP FILE HEADER
struct BITMAPFILEHEADER {
unsigned short bfType;
unsigned long bfSize;
unsigned short bfReserved1;
unsigned short bfReserved2;
unsigned long bfOffBits;
} bmfh;
bmfh.bfType='MB';
bmfh.bfSize=0; // TO DO
bmfh.bfReserved1 = bmfh.bfReserved2 = 0;
bmfh.bfOffBits = 54 + ((SaveBPP==24) ? 0 : (1<<SaveBPP)*4);
bmpfile.write ((char*)&bmfh,sizeof (bmfh));
// *2* SAVE BITMAP INFO HEADER
struct BITMAPINFOHEADER {
unsigned long biSize;
long biWidth;
long biHeight;
unsigned short biPlanes;
unsigned short biBitCount;
unsigned long biCompression;
unsigned long biSizeImage;
long biXPelsPerMeter;
long biYPelsPerMeter;
unsigned long biClrUsed;
unsigned long biClrImportant;
} bmih;
bmih.biSize=sizeof(bmih);
bmih.biWidth=Width;
bmih.biHeight=Height; // down-top
bmih.biPlanes=1;
bmih.biBitCount=SaveBPP;
bmih.biCompression=0;// BI_RGB?
bmih.biSizeImage =(Width*BPP)/8;
bmih.biSizeImage += (4- (bmih.biSizeImage)%4)%4;
bmih.biXPelsPerMeter=11811;
bmih.biYPelsPerMeter=11811;
bmih.biClrUsed=0;
bmih.biClrImportant=0;
bmpfile.write ((char*)&bmih,sizeof (bmih));
// *3* IF BPP AREN'T 24, SAVE PALETTE.
if (BPP!=24)
{
for (n=0;n< 1<<BPP;n++)
{
bmpfile.put(Palette[n].b);
bmpfile.put(Palette[n].g);
bmpfile.put(Palette[n].r);
bmpfile.put((char)0);
}
for (;n < 1<<SaveBPP; n++) // in case SaveBPP is higher than BPP
bmpfile.write((char*)'\0\0\0\0',4);
}
// *4* SAVE RASTER DATA
int PixelsPerByte = 8/SaveBPP; //used only if BPP are less than 8
int BitMask = (1<<SaveBPP)-1; //used only if BPP are less than 8
// Raster Data Rows are 32bit aligned in BMP files.
int RowAlignmentInFile = ((4- ((Width*SaveBPP+7)/8)%4)%4); // (bytes)
for (int row=0; row<Height; row++)
{
char * pPixel;
// If height is positive the bmp is bottom-up, set adequate row info:
pPixel= (char*) Raster + BytesPerRow *
( (bmih.biHeight>0)? Height-row-1 : row );
if (SaveBPP >= 8) // 8 or more BPP: Save as block.
bmpfile.write (pPixel, Width*SaveBPP/8);
else // Less than 8BPP: Save packing bytes.
{
unsigned char charToPut;
for (int col=0; col < Width; col+=PixelsPerByte)
{
charToPut=0;
for (int bit=8 ; bit >0 ; bit -= BPP) // high to low
charToPut |= (*pPixel++ & BitMask) << (bit - BPP);
bmpfile.put(charToPut);
}
}
// Ignore aligment bytes of file:
for (int m=0; m<RowAlignmentInFile; m++) bmpfile.put ((char)0);
}
bmpfile.close();
return 1;
}
// pre-declaration:
int LZWDecoder (char*, char*, short, int, int, int, const int);
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -