This section of the archives stores flipcode's complete Developer Toolbox collection, featuring a variety of mini-articles and source code contributions from our readers.

 

  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.

     

    Copyright 1999-2008 (C) FLIPCODE.COM and/or the original content author(s). All rights reserved.
    Please read our Terms, Conditions, and Privacy information.