|
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.
|