  | 
   Image Factory 
   Submitted by  |   
  
  
Hi, there hasn't been an update recently, so I thought I could contribute
with my image-factory. It's based on the generic-factory method described
in the expert's corner at cuj.com by Herb Sutter and Jim Hyslop.
This is basically two (and a half) things:
 
 
A generic abstract factory, to be used with all kinds of things.
An image abstract baseclass with two implementations: bmp_image and
  pcx_image.
(My reference counter class)
 
  The features are:
loading and saving of 24-bit bmp and pcx images.
portability, loading/saving works for both little and big-endian cpus.
plugability, when you've written a new image-class you only need to
  compile that class to plug it into the factory.
one function for all types BUT separate implementations.
 
  Here's an example:
// this will load a bmp-image, load_image will create a bmp_image object.
image_hnd my_image = load_image("my_image.bmp");
if(my_image.is_null()) // failure
  exit(1);
//
paint_bitmap(my_image-get_bits(), my_image-get_width(),
             my_image-get_height());
// this will save a pcx-image, save_image will create a pcx_image object
// if needed...
if(!save_image("my_image.pcx", my_image)) // fail to save
  exit(1);  |  
  
 
  Anyway for a more complete example look at the file win_main.cpp, which is
a simple program that loads a bmp or pcx image and draws it in a window.
I'm sorry if I don't make much sense, but it 2:30 in the morning and I'm a
bit tired.
But post here or mail me if you have any questions, I'll try to be
clearer when I'm awake!
  /Andreas Magnusson
 | 
 
 
 
Currently browsing [imagefactory.zip] (9,523 bytes) - [win_main.cpp] - (2,829 bytes)
 
 /********************************************************************************
*
*	File: win_main.cpp
*	Copyright(c) Andreas Magnusson 2002
*
*	Just very basic stuff...a testbed for my image-factory!
*
*	DISCLAIMER AND STUFF:
*	This source-code is supplied AS IS. I cannot be held responsible for any damage caused
*	by use or misuse of this source-code. So use the code as you please, but give credit
*	where they are due.
*
********************************************************************************/
#include <windows.h>
// disable the annoying warnings that comes up when you use map...
#pragma warning( disable : 4786)
#include "image.h"
  const char *CLASSNAME = "IMAGEVIEW", *WINNAME = "Image View";
  LRESULT CALLBACK WndProc(HWND hWnd, unsigned int iMessage, WPARAM wParam, LPARAM lParam);
  image_hnd img_array[5];
  int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE, LPSTR, int nCmdShow)
{
	HWND hWnd;
	MSG Message;
	WNDCLASS WndClass;
	ZeroMemory(&WndClass, sizeof(WNDCLASS));
	WndClass.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH);
	WndClass.hCursor = LoadCursor(NULL, IDC_ARROW);
	WndClass.hIcon = LoadIcon(hInstance, NULL);
	WndClass.hInstance = hInstance;
	WndClass.lpfnWndProc = WndProc;
	WndClass.lpszClassName = CLASSNAME;
	WndClass.style = CS_HREDRAW | CS_VREDRAW;
	if(!RegisterClass(&WndClass))
		return 0;
        
	hWnd = CreateWindow(CLASSNAME, WINNAME, WS_OVERLAPPEDWINDOW,
											CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT,
											NULL, NULL, hInstance, NULL);
  	img_array[0] = load_image("forest.bmp");
	save_image("forest.pcx", img_array[0]);
  	ShowWindow(hWnd, nCmdShow);
  	while(GetMessage(&Message, hWnd, 0, 0))
	{
		TranslateMessage(&Message);
		DispatchMessage(&Message);
	}
	return Message.wParam;
}
  COLORREF make_color(const unsigned char *buf)
{
	COLORREF cl = buf[0] | (buf[1] << 8) | (buf[2] << 16);
	return cl;
}
  void draw_image(HDC hdc, int ystart, image_hnd &img)
{
	if(img.is_null())
		return;
	for(int y = 0; y < img->get_height(); y++)
	{
		for(int x = 0; x < img->get_width(); x++)
		{
			COLORREF cl = make_color(&img->get_bits()[y * 3 * img->get_width() + x * 3]);
			SetPixel(hdc, x, y + ystart, cl);
		}
	}
}
  LRESULT CALLBACK WndProc(HWND hWnd, unsigned int iMessage, WPARAM wParam, LPARAM lParam)
{
	PAINTSTRUCT ps;
	int ystart, i;
	switch(iMessage)
	{
	case WM_PAINT:
		BeginPaint(hWnd, &ps);
		ystart = 0;
		for(i = 0; i < 5; i++)
		{
			if(!img_array[i].is_null())
			{
				draw_image(ps.hdc, ystart, img_array[i]);
				ystart += img_array[i]->get_height() + 1;
			}
		}
		EndPaint(hWnd, &ps);
		break;
	case WM_CLOSE:
		PostQuitMessage(0);
		break;
	default:
		return DefWindowProc(hWnd, iMessage, wParam, lParam);
	}
	return 0;
}
     |  
  
 | 
 
  
Currently browsing [imagefactory.zip] (9,523 bytes) - [generic_factory.h] - (1,854 bytes)
 
 /**************************************************************************
*
*	File: generic_factory.h
*
*	This file is basically what Herb Sutter and Jim Hyslop show in an article
*	on http://www.cuj.com/ so I can't really take any credit for it.
*
*
*	DISCLAIMER AND STUFF:
*	This source-code is supplied AS IS. I cannot be held responsible for any damage caused
*	by use or misuse of this source-code nor any derivatives of it.
*	So use the code as you please, but give credit where they are due.
*
**************************************************************************/
#ifndef __GENERIC_FACTORY_H__
#define __GENERIC_FACTORY_H__
  #include <map>
#include <string>
#include "handle.h"
  template <class prod_type, typename class_id = std::string>
class generic_factory
{
	typedef handle<prod_type> (*base_type_fn)();
	typedef std::map<class_id, base_type_fn> registry_t;
	registry_t registry;
	generic_factory() {}
	generic_factory(const generic_factory &); // not implemented
	generic_factory &operator=(const generic_factory &); // not implemented
public:
	static generic_factory &instance()
	{
		static generic_factory gf;
		return gf;
	}
	void register_type(const class_id &key, base_type_fn fn)
	{
		registry[key] = fn;
	}
	handle<prod_type> create(const class_id &key) const
	{
		handle<prod_type> obj;
		registry_t::const_iterator entry = registry.find(key);
		if(entry != registry.end())
			obj = entry->second();
		return obj;
	}
};
  template <class parent_t, class self_t, typename classid_t = std::string>
class register_in_factory
{
public:
	static handle<parent_t> create_instance()
	{
		return handle<parent_t>(new self_t);
	}
	register_in_factory(const classid_t &key)
	{
		generic_factory<parent_t>::instance().register_type(key, create_instance);
	}
};
  
#endif
     |  
  
 | 
 
  
Currently browsing [imagefactory.zip] (9,523 bytes) - [handle.h] - (1,799 bytes)
 
 /****************************************************************
*
*	File: handle.h
*	Copyright(c) Andreas Magnusson 2002
*
*	This is my classes for reference counted objects.
*
*	DISCLAIMER AND STUFF:
*	This source-code is supplied AS IS. I cannot be held responsible for any damage caused
*	by use or misuse of this source-code nor any derivatives of it.
*	So use the code as you please, but give credit where they are due.
*
****************************************************************/
#ifndef __HANDLE_H__
#define __HANDLE_H__
  class ref_counted
{
	int _ref_count;
public:
	ref_counted() : _ref_count(0) {}
	virtual ~ref_counted() {}
	int add_ref() {return ++_ref_count;}
	int release() {return --_ref_count;}
};
  template<class T> class handle
{
	T *object;
	void release()
	{
		if(object)
		{
			if(object->release() == 0)
				delete object;
		}
	}
	void add_ref()
	{
		if(object)
			object->add_ref();
	}
	void assign(T *ptr)
	{
		if(ptr == object)
			return;
		release();
		object = ptr;
		add_ref();
	}
public:
	handle() : object(0) {}
	handle(T *pNew)
	{
		object = pNew;
		add_ref();
	}
	handle(const handle &hnd)
	{
		object = hnd.object;
		add_ref();
	}
	~handle()
	{
		release();
	}
	const handle &operator =(const handle &hnd)
	{
		assign(hnd.object);
		return *this;
	}
	const handle &operator =(T *pNew)
	{
		assign(pNew);
		return *this;
	}
	T *operator ->()
	{
		return object;
	}
	operator T *()
	{
		return object;
	}
	T &operator *()
	{
		return *object;
	}
	bool operator ==(const handle &hnd)
	{
		return object == hnd.object;
	}
	bool operator !=(const handle &hnd)
	{
		return object != hnd.object;
	}
	bool is_null()
	{
		return object == NULL;
	}
};
  
#endif
     |  
  
 | 
 
  
Currently browsing [imagefactory.zip] (9,523 bytes) - [image.cpp] - (2,203 bytes)
 
 /*************************************************************************
*
*	File: image.cpp
*	Copyright(c) Andreas Magnusson 2002
*
*	This is the image implementation...
*
*	DISCLAIMER AND STUFF:
*	This source-code is supplied AS IS. I cannot be held responsible for any damage caused
*	by use or misuse of this source-code nor any derivatives of it.
*	So use the code as you please, but give credit where they are due.
*
*************************************************************************/
  // disable the annoying warnings that comes up when you use map...
#pragma warning( disable : 4786)
#include "image.h"
#include <stdio.h>
  image::image()
:width(0), height(0), buffer(0), color_depth(0)
{
}
  image::image(const image &img)
:width(img.width), height(img.height), color_depth(img.color_depth)
{
	int size = height * width * (color_depth >> 3);
	buffer = new unsigned char[size];
	memcpy(buffer, img.buffer, size);
}
  image::~image()
{
	if(buffer)
		delete[] buffer;
}
  bool image::copy(const image &img)
{
	width = img.get_width();
	height = img.get_height();
	color_depth = img.get_color_depth();
	long size = height * width * (color_depth >> 3);
	buffer = new unsigned char[size];
	if(!buffer)
		return false;
	memcpy(buffer, img.get_bits(), size);
	return true;
}
  ///////////////////////////////
image_hnd load_image(const std::string &file_name)
{
	int p = file_name.find_last_of('.');
	std::string suffix;
	if(p != std::string::npos)
		suffix = file_name.substr(p + 1);
  	image_hnd img = image_factory::instance().create(suffix);
	if(img.is_null())
		return img;
  	if(img->load(file_name))
		return img;
  	return handle<image>(0);
}
  bool save_image(const std::string &file_name, image_hnd &src)
{
	int p = file_name.find_last_of('.');
	std::string suffix;
	if(p != std::string::npos)
		suffix = file_name.substr(p + 1);
  	if(_stricmp(suffix.c_str(), src->get_type()) != 0)
	{
		image_hnd img = image_factory::instance().create(suffix);
		if(img.is_null())
			return false;
  		if(!img->copy(*src))
			return false;
  		return img->save(file_name);
	}
	else
		return src->save(file_name);
}
     |  
  
 | 
 
  
Currently browsing [imagefactory.zip] (9,523 bytes) - [image.h] - (1,612 bytes)
 
 /*********************************************************************************
*
*	File: image.h
* Copyright(c) Andreas Magnusson 2002
*
*
*	DISCLAIMER AND STUFF:
*	This source-code is supplied AS IS. I cannot be held responsible for any damage caused
*	by use or misuse of this source-code nor any derivatives of it.
*	So use the code as you please, but give credit where they are due.
*
*********************************************************************************/
#ifndef __IMAGE_H__
#define __IMAGE_H__
  #include "generic_factory.h"
#include "handle.h"
  enum IMAGE_COLOR_DEPTH {IMAGE_2_BITS = 2, IMAGE_4_BITS = 4, IMAGE_8_BITS = 8,
											IMAGE_16_BITS = 16, IMAGE_24_BITS = 24, IMAGE_32_BITS = 32};
  class image : public ref_counted
{
	void operator =(const image &img); // not implemented on purpose!
protected:
	int width, height, color_depth;
	unsigned char *buffer;
public:
	image();
	image(const image &img);
	virtual ~image();
	//
	virtual unsigned char *get_bits() const {return buffer;}
	virtual int get_width() const {return width;}
	virtual int get_height() const {return height;}
	virtual int get_color_depth() const {return color_depth;}
	virtual bool copy(const image &img);
	//
	virtual bool load(const std::string &file_name) = 0;
	virtual bool save(const std::string &file_name) = 0;
	virtual const char *get_type() = 0;
};
  typedef handle<image> image_hnd;
typedef generic_factory<image> image_factory;
image_hnd load_image(const std::string &file_name);
bool save_image(const std::string &file_name, image_hnd &img);
  #endif
     |  
  
 | 
 
  
Currently browsing [imagefactory.zip] (9,523 bytes) - [pcx.cpp] - (8,606 bytes)
 
 /*************************************************************************
*
*	File: pcx.cpp
*	Copyright(c) Andreas Magnusson 2002
*
*	Should work on both big-endian (eg. Sun Sparc) and little-endian (eg. Intel x86)
*	machines.
*
*	DISCLAIMER AND STUFF:
*	This source-code is supplied AS IS. I cannot be held responsible for any damage caused
*	by use or misuse of this source-code nor any derivatives of it.
*	So use the code as you please, but give credit where they are due.
*
*************************************************************************/
  // disable the annoying warnings that comes up when you use map...
#pragma warning( disable : 4786)
#include <stdio.h>
#include "image.h"
  struct pcx_header
{
  unsigned char manufacturer;
  unsigned char version;
  unsigned char encoding;
  unsigned char bits_per_pixel;
  unsigned short x, y;
  unsigned short width, height;
  unsigned short horz_res;
  unsigned short vert_res;
  unsigned char ega_palette[48];
  unsigned char reserved;
  unsigned char num_color_planes;
  unsigned short bytes_per_line;
  unsigned short palette_type;
  unsigned char padding[58];
	//
	unsigned short make_word(unsigned char *&buf)
	{
		unsigned short rv = *buf++;
		rv += (*buf++ << 8);
		return rv;
	}
	void word2byte(unsigned short v, unsigned char *&buf)
	{
		*buf++ = v & 0xff;
		*buf++ = (v >> 8) & 0xff;
	}
	//
	pcx_header(unsigned char *temphead)
	{
	  // this procedure is needed for compatibility between
		// little-endian machines (eg Intel-based) and big-endian
		// machines (eg Sun Sparc)
	  manufacturer = *temphead++;
		version = *temphead++;
	  encoding = *temphead++;
		bits_per_pixel = *temphead++;
	  x = make_word(temphead);
		y = make_word(temphead);
	  width = make_word(temphead);
		height = make_word(temphead);
  	  horz_res = make_word(temphead);
		vert_res = make_word(temphead);
  	  // I doubt I will ever use EGA-palettes so I don't copy their
		// contents to the header.
	  //  char ega_palette[48];
		temphead += sizeof(ega_palette);
  		reserved = *temphead++;
	  num_color_planes = *temphead++;
		bytes_per_line = make_word(temphead);
		palette_type = make_word(temphead);
		//
	}
	pcx_header()
	{
	}
	void copy_to_buffer(unsigned char *tempbuf)
	{
		//memcpy(tempbuf, this, sizeof(pcx_header));
		memset(tempbuf, 0, sizeof(pcx_header));
		*tempbuf++ = manufacturer;
		*tempbuf++ = version;
		*tempbuf++ = encoding;
		*tempbuf++ = bits_per_pixel;
		word2byte(x, tempbuf);
		word2byte(y, tempbuf);
		word2byte(width, tempbuf);
		word2byte(height, tempbuf);
		word2byte(horz_res, tempbuf);
		word2byte(vert_res, tempbuf);
		tempbuf += sizeof(ega_palette);
		*tempbuf++ = reserved;
		*tempbuf++ = num_color_planes;
		word2byte(bytes_per_line, tempbuf);
		word2byte(palette_type, tempbuf);
	}
};
  ///////////////////////////////////////////////////////////////////////////////////////
class pcx_image : public image
{
	unsigned char *read_line24(unsigned char *buf, unsigned long line, unsigned long sv);
	unsigned char *write_line24(unsigned char *buf, unsigned long line, unsigned long sv);
public:
	pcx_image();
	virtual bool load(const std::string &file_name);
	virtual bool save(const std::string &file_name);
	virtual const char *get_type() {return "pcx";}
};
  // register pcx_image
namespace
{
	register_in_factory<image, pcx_image> register_me("pcx");
};
  pcx_image::pcx_image()
{
}
  // this function currently only reads 24-bit pcx-files
bool pcx_image::load(const std::string &file_name)
{
	FILE *file;
  	file = fopen(file_name.c_str(), "rb");
	if(!file)
		return false;
  	fseek(file, 0, SEEK_END);
	long file_size = ftell(file) - sizeof(pcx_header);
	rewind(file);
  	unsigned char *temphead = new unsigned char[sizeof(pcx_header)];
	fread(temphead, 1, sizeof(pcx_header), file);
	pcx_header header(temphead);
	delete[] temphead;
  	width = header.width + 1;
	height = header.height + 1;
	color_depth = header.num_color_planes << 3;
  	long size = header.bytes_per_line * get_height() * header.num_color_planes;
	if(buffer)
		delete[] buffer;
  	unsigned char *tmpbuf = new unsigned char[file_size];
	unsigned char *svtmpbuf = tmpbuf; // to delete tmpbuf later...
  
	buffer = new unsigned char[size * 2];
	if(buffer == NULL || tmpbuf == NULL)
	{
		fclose(file);
		return false;
	}
  	memset(buffer, 0, size);
	fread(tmpbuf, 1, file_size, file);
	fclose(file);
  	// the data is stored as bitplanes in the pcx-image, thus first a row of red, then a row
	// of green and finally a row of blue. Then comes next row of red...theoretically this
	// could be used to save alpha-values in pcx-images, but ASFAIK no paint-program supports
	// that...
	for(int i = 0; i < get_height(); i++)
	{
		for(int j = 0; j < (get_color_depth() >> 3); j++)
			tmpbuf = read_line24(tmpbuf, i * width, j);
	}
  	delete[] svtmpbuf;
	return true;
}
  bool pcx_image::save(const std::string &file_name)
{
	if(!buffer)
		return false;
  	long size = get_width() * get_height() * (get_color_depth() >> 3);
	unsigned char *pack = NULL, *tmppack;
  	// hopefully the amount of bytes packed will never
	// be bigger than the original size, but if it does
	// try making it bigger. OBSERVE that it will if your
	// image consists of a lot of vertical lines and the
	// lines are drawn with a color above 191
	// so to be on the safe side we allocate twice that...
	// we should of course process the image and calculate
	// the number of bytes required...
	pack = new unsigned char[size * 2];
	if(!pack)
		return false;
	tmppack = pack;
  	FILE *file;
  	file = fopen(file_name.c_str(), "wb");
	if(!file)
	{
		delete[] pack;
		return false;
	}
  	// setup pcxheader to standard values
  unsigned char *temphead = new unsigned char[sizeof(pcx_header)];
	pcx_header header;
	header.manufacturer = 10;
	header.version = 5;
	header.encoding = 1;
	header.bits_per_pixel = 8;
	header.x = 0;
	header.y = 0;
	header.height = get_height() - 1;
	header.width = get_width() - 1;
  	header.horz_res = 71; // ???
	header.vert_res = 71; // ???
	header.bytes_per_line = get_width();
	header.reserved = 0;
	header.num_color_planes = get_color_depth() >> 3;
	header.palette_type = 1;
	header.copy_to_buffer(temphead);
  	fwrite(temphead, 1, sizeof(pcx_header), file);
  	for(int i = 0; i < get_height(); i++)
	{
		for(int j = 0; j < (get_color_depth() >> 3); j++)
			tmppack = write_line24(tmppack, i * get_width(), j);
	}
  	fwrite(pack, 1, (long)tmppack - (long)pack, file);
  	fclose(file);
	delete[] temphead;
	delete[] pack;
	return true;
}
  // this writes an 24-bit PCX-encoded line used by save() (above)
unsigned char *pcx_image::write_line24(unsigned char *buf, unsigned long line, unsigned long in_pos)
{
	const unsigned long color_planes = get_color_depth() >> 3;
	unsigned char *read_buf = &buffer[line * color_planes];
	unsigned char last = read_buf[in_pos];
	int bpl = 0;
	int read_pos = in_pos + color_planes;
	short runlen = 1;
	for(int i = 1; i < get_width(); i++)
	{
		if(read_buf[read_pos] == last && runlen < 63)
		{
			runlen++;
			if(runlen == 63)
			{
				*buf++ = (unsigned char)((runlen | 0xc0) & 0xff);
				*buf++ = last;
				runlen = 0;
				bpl += 2;
			}
		}
		else
		{
			if(runlen > 1 || 0xc0 == (last & 0xc0))
			{
				*buf++ = (unsigned char)((runlen | 0xc0) & 0xff);
				bpl++;
			}
			*buf++ = last;
			bpl++;
			last = read_buf[read_pos];
			runlen = 1;
		}
		read_pos += color_planes;
	}
	// handle the last pixel too
	if(runlen)
	{
		if(runlen > 1 || 0xc0 == (last & 0xc0))
		{
			*buf++ = (unsigned char)((runlen | 0xc0) & 0xff);
			bpl++;
		}
		*buf++ = last;
		bpl++;
	}
	return buf;
}
  
unsigned char *pcx_image::read_line24(unsigned char *buf, unsigned long line, unsigned long sv)
{
	const unsigned long color_planes = get_color_depth() >> 3;
	unsigned long byte_count = 0, bytes_read = 0, write_pos = sv;
  unsigned char data;
  unsigned char *buffer24 = (unsigned char *)&buffer[line * color_planes];
  while(bytes_read < get_width())
  {
    data = *buf++;
    if((data >= 192) && (data <= 255))
    {
      byte_count = data - 192;
      data  = *buf++;
      while(byte_count-- > 0)
      {
				buffer24[write_pos] = data;
				write_pos += color_planes;
				bytes_read++;
      }
    }
    else
    {
      buffer24[write_pos] = data;
      write_pos += color_planes;
      bytes_read++;
    }
  }
  return buf;
}
   |  
  
 | 
 
  
Currently browsing [imagefactory.zip] (9,523 bytes) - [bmp.cpp] - (6,673 bytes)
 
 /*************************************************************************
*
*	File: bmp.cpp
*	Copyright(c) Andreas Magnusson 2002
*
*	This is my file for reading and writing bmp-files.
*
*	Should work on both big-endian (eg. Sun Sparc) and little-endian (eg. Intel x86)
*	machines.
*
*	DISCLAIMER AND STUFF:
*	This source-code is supplied AS IS. I cannot be held responsible for any damage caused
*	by use or misuse of this source-code nor any derivatives of it.
*	So use the code as you please, but give credit where they are due.
*
*************************************************************************/
  // disable the annoying warnings that comes up when you use map...
#pragma warning( disable : 4786)
#include "image.h"
#include <stdio.h>
  //////////////////////////////////
struct bmp_header
{
	char bm[2];
	unsigned long file_size;
	unsigned long reserved1;
	unsigned long data_offset;
	unsigned long bmp_header_size;
	unsigned long width;
	unsigned long height;
	unsigned short planes;
	unsigned short bpp;
	unsigned long compr;
	unsigned long bmp_data_size;
	unsigned long hres;
	unsigned long vres;
	unsigned long colors;
	unsigned long imp_colors;
	//
	unsigned long make_long(unsigned char *&buf)
	{
		unsigned long rv = *buf++;
		rv += (*buf++ << 8);
		rv += (*buf++ << 16);
		rv += (*buf++ << 24);
		return rv;
	}
	unsigned short make_word(unsigned char *&buf)
	{
		unsigned short rv = *buf++;
		rv += (*buf++ << 8);
		return rv;
	}
	void long2byte(unsigned long v, unsigned char *&buf)
	{
		*buf++ = v & 0xff;
		*buf++ = (v >> 8) & 0xff;
		*buf++ = (v >> 16) & 0xff;
		*buf++ = (v >> 24) & 0xff;
	}
	void word2byte(unsigned short v, unsigned char *&buf)
	{
		*buf++ = v & 0xff;
		*buf++ = (v >> 8) & 0xff;
	}
	bmp_header(unsigned char *temphead)
	{
	  // this procedure is needed for compatibility between
		// little-endian machines (eg Intel-based) and big-endian
		// machines (eg Sun Sparc)
		bm[0] = *temphead++;
		bm[1] = *temphead++;
		file_size = make_long(temphead);
		reserved1 = make_long(temphead);
		data_offset = make_long(temphead);
		bmp_header_size = make_long(temphead);
		width = make_long(temphead);
		height = make_long(temphead);
		planes = make_word(temphead);
		bpp = make_word(temphead);
		compr = make_long(temphead);
		bmp_data_size = make_long(temphead);
		hres = make_long(temphead);
		vres = make_long(temphead);
		colors = make_long(temphead);
		imp_colors = make_long(temphead);
		//
	}
	bmp_header()
	{
	}
	void copy_to_buffer(unsigned char *tempbuf)
	{
		*tempbuf++ = 'B'; //bm[0];
		*tempbuf++ = 'M'; //bm[1];
		long2byte(file_size, tempbuf);
		long2byte(reserved1, tempbuf);
		long2byte(data_offset, tempbuf);
		long2byte(bmp_header_size, tempbuf);
		long2byte(width, tempbuf);
		long2byte(height, tempbuf);
		word2byte(planes, tempbuf);
		word2byte(bpp, tempbuf);
		long2byte(compr, tempbuf);
		long2byte(bmp_data_size, tempbuf);
		long2byte(hres, tempbuf);
		long2byte(vres, tempbuf);
		long2byte(colors, tempbuf);
		long2byte(imp_colors, tempbuf);
	}
};
  ///////////////////////////////////////////////////////////////////////////////////
class bmp_image : public image
{
	void bgr2rgb();
	void rgb2bgr();
public:
	bmp_image();
	virtual bool load(const std::string &file_name);
	virtual bool save(const std::string &file_name);
	virtual const char *get_type() {return "bmp";}
};
  // register bmp_image to image factory
namespace
{
	register_in_factory<image, bmp_image> register_me("bmp");
};
  bmp_image::bmp_image()
{
}
  bool bmp_image::load(const std::string &file_name)
{
	FILE *file;
	
  file = fopen(file_name.c_str(), "rb");
	if(!file)
    return false;
  	unsigned char *temphead = new unsigned char[sizeof(bmp_header)];
	fread(temphead, 1, sizeof(bmp_header), file);
	bmp_header header(temphead);
	delete[] temphead;
  	if(strncmp(header.bm, "BM", 2) != 0)
	{
		fclose(file);
		return false;
	}
  	// currently only handles 24 and 32 bit images
	if(header.bpp < 24)
	{
		fclose(file);
		return false;
	}
  	width = header.width;
	height = header.height;
  	color_depth = header.bpp;
  	int ch_count = get_color_depth() >> 3;
  	long size = width * height * ch_count;
  	if(buffer)
		delete[] buffer;
  
	buffer = new unsigned char[size];
	if(buffer == NULL)
	{
		fclose(file);
		return false;
	}
  	if(ftell(file) != header.data_offset)
		fseek(file, header.data_offset, SEEK_SET);
  	// the bmp-image is read into the buffer backwards, since it seems to be stored
	// upside down...
	int oneline = get_width() * ch_count;
	int offset = size;
	for(int i = 0; i < size; i += oneline)
	{
		fread(&buffer[offset - oneline], 1, oneline, file);
		offset -= oneline;
	}
	fclose(file);
  	// convert to rgb
	bgr2rgb();
  	return true;
}
  bool bmp_image::save(const std::string &file_name)
{
	bmp_header header;
	header.bpp = get_color_depth();
	header.colors = 0;
	header.imp_colors = 0;
	header.compr = 0;
	header.height = get_height();
	header.width = get_width();
	header.planes = 1;
	header.bmp_data_size = get_width() * get_height() * (get_color_depth() >> 3);
	header.bmp_header_size = 0x28;
	header.data_offset = sizeof(bmp_header);
	header.file_size = header.bmp_data_size + header.bmp_header_size;
	header.hres = 2834;
	header.vres = 2834;
	header.reserved1 = 0;
	//
	unsigned char *temphead = new unsigned char[sizeof(bmp_header)];
	if(!temphead)
		return false;
  	FILE *fp = fopen(file_name.c_str(), "wb");
	if(!fp)
	{
		delete[] temphead;
		return false;
	}
  	header.copy_to_buffer(temphead);
	fwrite(temphead, 1, sizeof(bmp_header), fp);
  	// convert from rgb to bgr (since bmp seems to be that way)
	bgr2rgb();
  	// write the image backwards, since that seems to be right...
	int oneline = get_width() * (get_color_depth() >> 3);
	unsigned long size = oneline * get_height();
	int offset = size;
	for(int i = 0; i < size; i += oneline)
	{
		fwrite(&buffer[offset - oneline], 1, oneline, fp);
		offset -= oneline;
	}
	fclose(fp);
	delete[] temphead;
  	// convert the buffer back to rgb, since that is standard in my library.
	bgr2rgb();
	return true;
}
  ///
// this routine swaps the blue and red components since bmp seems to be in BGR format
// instead of rgb.
void bmp_image::bgr2rgb()
{
	const int color_planes = get_color_depth() >> 3;
	int size = get_width() * get_height() * color_planes;
	unsigned char tmp;
	for(int i = 0; i < size; i += color_planes)
	{
		tmp = buffer[i];
		buffer[i] = buffer[i + 2];
		buffer[i + 2] = tmp;
	}
}
   |  
  
 | 
 
 
 
The zip file viewer built into the Developer Toolbox made use
of the zlib library, as well as the zlibdll source additions.
 
 
 |