00001 #ifndef BITMAP_IMPLEMENTATION_FILE
00002 #define BITMAP_IMPLEMENTATION_FILE
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018 #include "bitmap.h"
00019 #include "palette.h"
00020
00021 #include <basis/array.h>
00022 #include <basis/convert_utf.h>
00023 #include <basis/function.h>
00024 #include <basis/istring.h>
00025 #include <basis/portable.h>
00026 #include <opsystem/byte_filer.h>
00027
00028 #include <memory.h>
00029
00030 #define WIDTH(rectang) absolute_value((rectang).right - (rectang).left)
00031 #define HEIGHT(rectang) absolute_value((rectang).bottom - (rectang).top)
00032
00033
00034
00035 bitmap::bitmap()
00036 : _valid(false), _file_header(), _info(NIL), _header(NIL), _color_table(NIL),
00037 _the_bits(NIL), _colors(0), _optional_global(NIL), _palette(new palette())
00038 {}
00039
00040 bitmap::bitmap(const istring &filename)
00041 : _valid(false), _file_header(), _info(NIL), _header(NIL), _color_table(NIL),
00042 _the_bits(NIL), _colors(0), _optional_global(NIL), _palette(new palette())
00043 { load_from_file(filename); }
00044
00045 bitmap::bitmap(application_instance instance, const char *resource)
00046 : _valid(false), _file_header(), _info(NIL), _header(NIL), _color_table(NIL),
00047 _the_bits(NIL), _colors(0), _optional_global(NIL), _palette(new palette())
00048 { load_from_resource(instance, resource); }
00049
00050 bitmap::bitmap(HGLOBAL global)
00051 : _valid(false), _file_header(), _info(NIL), _header(NIL), _color_table(NIL),
00052 _the_bits(NIL), _colors(0), _optional_global(NIL), _palette(new palette())
00053 { load_from_global(global); }
00054
00055 bitmap::~bitmap()
00056 {
00057 reset();
00058 delete _palette;
00059 _palette = NIL;
00060 }
00061
00062 void bitmap::reset()
00063 {
00064 _valid = false;
00065 if (_optional_global) {
00066
00067 UnlockResource(_optional_global);
00068 FreeResource(_optional_global);
00069 _optional_global = NIL;
00070 } else {
00071
00072 delete [] _info;
00073 }
00074 _palette->reset();
00075 _info = NIL;
00076 _header = NIL;
00077 _color_table = NIL;
00078 _the_bits = NIL;
00079 _colors = 0;
00080 }
00081
00082 bool bitmap::load_from_resource(application_instance instance,
00083 const char *resource)
00084 {
00085 reset();
00086
00087 HRSRC hrsrc = FindResource(instance, to_unicode_temp(resource), RT_BITMAP);
00088 if (!hrsrc) return false;
00089
00090 HGLOBAL glob = LoadResource(instance, hrsrc);
00091
00092 return load_from_global(glob);
00093 }
00094
00095 bool bitmap::load_from_global(HGLOBAL glob)
00096 {
00097 reset();
00098 _optional_global = glob;
00099
00100 _info = (LPBITMAPINFO)LockResource(_optional_global);
00101 make_pointers_valid(true);
00102 return true;
00103 }
00104
00105 bool bitmap::load_from_file(const istring &filename)
00106 {
00107 reset();
00108
00109 byte_filer bitfile(filename, "rb");
00110 if (!bitfile.good()) { bitfile.close(); return false; }
00111 int file_len = int(bitfile.length());
00112
00113
00114
00115 int read = bitfile.read((byte *)&_file_header, sizeof(_file_header));
00116 if (read != sizeof(_file_header)) {
00117
00118 reset(); bitfile.close(); return false;
00119 }
00120
00121
00122 if (_file_header.bfType != 0x4d42) {
00123
00124 reset(); bitfile.close(); return false;
00125 }
00126
00127
00128 BITMAPINFOHEADER temp_header;
00129 read = bitfile.read((byte *)&temp_header, sizeof(temp_header));
00130 if (read != sizeof(temp_header)) {
00131
00132 reset(); bitfile.close(); return false;
00133 }
00134
00135
00136
00137 if (temp_header.biSize != sizeof(BITMAPINFOHEADER)) {
00138 if (temp_header.biSize != sizeof(BITMAPCOREHEADER)) {
00139
00140 reset(); bitfile.close(); return false;
00141 }
00142 reset(); bitfile.close(); return false;
00143
00144 }
00145
00146
00147 _header = &temp_header;
00148 int colors_used = colors();
00149 _header = NIL;
00150
00151 if (!colors_used) {
00152
00153 reset(); bitfile.close(); return false;
00154 }
00155
00156
00157 temp_header.biClrUsed = 256;
00158 temp_header.biBitCount = 8;
00159
00160 int just_bits_size = _file_header.bfSize - _file_header.bfOffBits;
00161 int full_size = sizeof(temp_header) + 256 * sizeof(RGBQUAD) + just_bits_size;
00162
00163
00164
00165
00166 byte *DIB_chunk = new byte[full_size];
00167 memset(DIB_chunk, 0, full_size);
00168 memcpy(DIB_chunk, (byte *)&temp_header, sizeof(temp_header));
00169
00170
00171 int stored_color_table_size = colors_used * sizeof(RGBQUAD);
00172 read = bitfile.read(DIB_chunk + sizeof(temp_header),
00173 stored_color_table_size);
00174
00175 if (read != stored_color_table_size) {
00176
00177 reset(); bitfile.close(); return false;
00178 }
00179
00180
00181
00182 if (file_len < int(sizeof(_file_header) + sizeof(temp_header))
00183 + stored_color_table_size + just_bits_size) {
00184
00185 reset(); bitfile.close(); return false;
00186 }
00187
00188
00189 bitfile.seek(_file_header.bfOffBits, byte_filer::FROM_START);
00190
00191 int chunk_offset = sizeof(temp_header) + 256 * sizeof(RGBQUAD);
00192 int bytes_read = bitfile.read(DIB_chunk + chunk_offset, just_bits_size);
00193 bitfile.close();
00194 if (bytes_read != just_bits_size) {
00195
00196 reset(); return false;
00197 }
00198
00199
00200 _info = (BITMAPINFO *)DIB_chunk;
00201
00202 make_pointers_valid(false);
00203
00204 return true;
00205 }
00206
00207 void bitmap::make_pointers_valid(bool read_only)
00208 {
00209 if (!_info) return;
00210
00211 _header = (BITMAPINFOHEADER *)_info;
00212
00213 _color_table = (RGBQUAD *)((byte *)_info + _header->biSize);
00214
00215
00216
00217
00218
00219 _colors = colors();
00220
00221 if (!read_only) {
00222
00223 _header->biSizeImage = image_size();
00224
00225 _header->biClrUsed = _colors;
00226 }
00227
00228
00229
00230 int color_table_size = _colors * sizeof(RGBQUAD);
00231 _the_bits = (byte *) ((byte *)_info + _header->biSize + color_table_size);
00232
00233 _valid = true;
00234
00235
00236
00237 retrieve_palette(*_palette);
00238 }
00239
00240 int bitmap::image_size() const
00241 {
00242 if (!_header->biSizeImage) {
00243
00244 int width_in_bytes = width();
00245 int size_of_image = width_in_bytes * height();
00246 return size_of_image;
00247 } else {
00248
00249 return _header->biSizeImage;
00250 }
00251 }
00252
00253 int bitmap::width() const { return _header->biWidth; }
00254
00255 int bitmap::height() const { return _header->biHeight; }
00256
00257 int bitmap::colors() const
00258 {
00259 if (!_header) return 0;
00260 if (_header->biClrUsed) return _header->biClrUsed;
00261
00262 if (_header->biBitCount <= 8) return 1 << _header->biBitCount;
00263
00264 return 0;
00265 }
00266
00267 BITMAPINFOHEADER *bitmap::get_header() const { return _header; }
00268
00269 BITMAPINFO *bitmap::get_info() const { return _info; }
00270
00271 RGBQUAD *bitmap::get_color_table() const { return _color_table; }
00272
00273 byte *bitmap::get_bits() const { return _the_bits; }
00274
00275 bool bitmap::paint(HDC context, const RECT &update_rectangle,
00276 const RECT &bitmap_portion) const
00277 {
00278 if (!valid()) return false;
00279
00280 HPALETTE old_palette = NIL;
00281 if (_palette->win_palette()) {
00282
00283 old_palette = SelectPalette(context, _palette->win_palette(), false);
00284
00285 }
00286
00287
00288 SetStretchBltMode(context, COLORONCOLOR);
00289
00290
00291 RealizePalette(context);
00292
00293 BOOL to_return;
00294 if ( (WIDTH(update_rectangle) == WIDTH(bitmap_portion)) &&
00295 (HEIGHT(update_rectangle) == HEIGHT(bitmap_portion))) {
00296
00297 to_return = ::SetDIBitsToDevice(context, update_rectangle.left,
00298 update_rectangle.top, WIDTH(update_rectangle),
00299 HEIGHT(update_rectangle), bitmap_portion.left,
00300 (int)height() - bitmap_portion.top - HEIGHT(bitmap_portion),
00301 0, (WORD)height(), _the_bits, _info, DIB_RGB_COLORS);
00302 } else {
00303
00304 to_return = ::StretchDIBits(context, update_rectangle.left,
00305 update_rectangle.top, WIDTH(update_rectangle),
00306 HEIGHT(update_rectangle), bitmap_portion.left, bitmap_portion.top,
00307 WIDTH(bitmap_portion), HEIGHT(bitmap_portion), _the_bits, _info,
00308 DIB_RGB_COLORS, SRCCOPY);
00309 }
00310
00311
00312 if (_palette->win_palette() && old_palette) {
00313 ::SelectPalette(context, old_palette, true);
00314 }
00315
00316 return to_return;
00317 }
00318
00319 bool bitmap::retrieve_palette(palette &to_fill) const
00320 {
00321 if (!valid()) return false;
00322 to_fill = palette(colors(), get_color_table());
00323 return to_fill.valid();
00324 }
00325
00326
00327 #endif //BITMAP_IMPLEMENTATION_FILE
00328