1 //---------------------------------------------------------------------------- 2 // 3 //---------------------------------------------------------------------------- 4 // Contact: mcseemagg@yahoo.com 5 //---------------------------------------------------------------------------- 6 // 7 // class pixel_map 8 // 9 //---------------------------------------------------------------------------- 10 11 #include "platform/win32/agg_win32_bmp.h" 12 #include "agg_basics.h" 13 14 namespace agg 15 { 16 17 //------------------------------------------------------------------------ ~pixel_map()18 pixel_map::~pixel_map() 19 { 20 destroy(); 21 } 22 23 24 //------------------------------------------------------------------------ pixel_map()25 pixel_map::pixel_map() : 26 m_bmp(0), 27 m_buf(0), 28 m_bpp(0), 29 m_is_internal(false), 30 m_img_size(0), 31 m_full_size(0) 32 33 { 34 } 35 36 37 //------------------------------------------------------------------------ destroy()38 void pixel_map::destroy() 39 { 40 if(m_bmp && m_is_internal) delete [] (unsigned char*)m_bmp; 41 m_bmp = 0; 42 m_is_internal = false; 43 m_buf = 0; 44 } 45 46 47 //------------------------------------------------------------------------ create(unsigned width,unsigned height,org_e org,unsigned clear_val)48 void pixel_map::create(unsigned width, 49 unsigned height, 50 org_e org, 51 unsigned clear_val) 52 { 53 destroy(); 54 if(width == 0) width = 1; 55 if(height == 0) height = 1; 56 m_bpp = org; 57 create_from_bmp(create_bitmap_info(width, height, m_bpp)); 58 create_gray_scale_palette(m_bmp); 59 m_is_internal = true; 60 if(clear_val <= 255) 61 { 62 memset(m_buf, clear_val, m_img_size); 63 } 64 } 65 66 67 //------------------------------------------------------------------------ create_dib_section(HDC h_dc,unsigned width,unsigned height,org_e org,unsigned clear_val)68 HBITMAP pixel_map::create_dib_section(HDC h_dc, 69 unsigned width, 70 unsigned height, 71 org_e org, 72 unsigned clear_val) 73 { 74 destroy(); 75 if(width == 0) width = 1; 76 if(height == 0) height = 1; 77 m_bpp = org; 78 HBITMAP h_bitmap = create_dib_section_from_args(h_dc, width, height, m_bpp); 79 create_gray_scale_palette(m_bmp); 80 m_is_internal = true; 81 if(clear_val <= 255) 82 { 83 memset(m_buf, clear_val, m_img_size); 84 } 85 return h_bitmap; 86 } 87 88 89 90 //------------------------------------------------------------------------ clear(unsigned clear_val)91 void pixel_map::clear(unsigned clear_val) 92 { 93 if(m_buf) memset(m_buf, clear_val, m_img_size); 94 } 95 96 97 //------------------------------------------------------------------------ attach_to_bmp(BITMAPINFO * bmp)98 void pixel_map::attach_to_bmp(BITMAPINFO *bmp) 99 { 100 if(bmp) 101 { 102 destroy(); 103 create_from_bmp(bmp); 104 m_is_internal = false; 105 } 106 } 107 108 109 110 //static 111 //------------------------------------------------------------------------ calc_full_size(BITMAPINFO * bmp)112 unsigned pixel_map::calc_full_size(BITMAPINFO *bmp) 113 { 114 if(bmp == 0) return 0; 115 116 return sizeof(BITMAPINFOHEADER) + 117 sizeof(RGBQUAD) * calc_palette_size(bmp) + 118 bmp->bmiHeader.biSizeImage; 119 } 120 121 //static 122 //------------------------------------------------------------------------ calc_header_size(BITMAPINFO * bmp)123 unsigned pixel_map::calc_header_size(BITMAPINFO *bmp) 124 { 125 if(bmp == 0) return 0; 126 return sizeof(BITMAPINFOHEADER) + sizeof(RGBQUAD) * calc_palette_size(bmp); 127 } 128 129 130 //static 131 //------------------------------------------------------------------------ calc_palette_size(unsigned clr_used,unsigned bits_per_pixel)132 unsigned pixel_map::calc_palette_size(unsigned clr_used, unsigned bits_per_pixel) 133 { 134 int palette_size = 0; 135 136 if(bits_per_pixel <= 8) 137 { 138 palette_size = clr_used; 139 if(palette_size == 0) 140 { 141 palette_size = 1 << bits_per_pixel; 142 } 143 } 144 return palette_size; 145 } 146 147 //static 148 //------------------------------------------------------------------------ calc_palette_size(BITMAPINFO * bmp)149 unsigned pixel_map::calc_palette_size(BITMAPINFO *bmp) 150 { 151 if(bmp == 0) return 0; 152 return calc_palette_size(bmp->bmiHeader.biClrUsed, bmp->bmiHeader.biBitCount); 153 } 154 155 156 //static 157 //------------------------------------------------------------------------ calc_img_ptr(BITMAPINFO * bmp)158 unsigned char * pixel_map::calc_img_ptr(BITMAPINFO *bmp) 159 { 160 if(bmp == 0) return 0; 161 return ((unsigned char*)bmp) + calc_header_size(bmp); 162 } 163 164 //static 165 //------------------------------------------------------------------------ create_bitmap_info(unsigned width,unsigned height,unsigned bits_per_pixel)166 BITMAPINFO* pixel_map::create_bitmap_info(unsigned width, 167 unsigned height, 168 unsigned bits_per_pixel) 169 { 170 unsigned line_len = calc_row_len(width, bits_per_pixel); 171 unsigned img_size = line_len * height; 172 unsigned rgb_size = calc_palette_size(0, bits_per_pixel) * sizeof(RGBQUAD); 173 unsigned full_size = sizeof(BITMAPINFOHEADER) + rgb_size + img_size; 174 175 BITMAPINFO *bmp = (BITMAPINFO *) new unsigned char[full_size]; 176 177 bmp->bmiHeader.biSize = sizeof(BITMAPINFOHEADER); 178 bmp->bmiHeader.biWidth = width; 179 bmp->bmiHeader.biHeight = height; 180 bmp->bmiHeader.biPlanes = 1; 181 bmp->bmiHeader.biBitCount = (unsigned short)bits_per_pixel; 182 bmp->bmiHeader.biCompression = 0; 183 bmp->bmiHeader.biSizeImage = img_size; 184 bmp->bmiHeader.biXPelsPerMeter = 0; 185 bmp->bmiHeader.biYPelsPerMeter = 0; 186 bmp->bmiHeader.biClrUsed = 0; 187 bmp->bmiHeader.biClrImportant = 0; 188 189 return bmp; 190 } 191 192 193 //static 194 //------------------------------------------------------------------------ create_gray_scale_palette(BITMAPINFO * bmp)195 void pixel_map::create_gray_scale_palette(BITMAPINFO *bmp) 196 { 197 if(bmp == 0) return; 198 199 unsigned rgb_size = calc_palette_size(bmp); 200 RGBQUAD *rgb = (RGBQUAD*)(((unsigned char*)bmp) + sizeof(BITMAPINFOHEADER)); 201 unsigned brightness; 202 unsigned i; 203 204 for(i = 0; i < rgb_size; i++) 205 { 206 brightness = (255 * i) / (rgb_size - 1); 207 rgb->rgbBlue = 208 rgb->rgbGreen = 209 rgb->rgbRed = (unsigned char)brightness; 210 rgb->rgbReserved = 0; 211 rgb++; 212 } 213 } 214 215 216 217 //static 218 //------------------------------------------------------------------------ calc_row_len(unsigned width,unsigned bits_per_pixel)219 unsigned pixel_map::calc_row_len(unsigned width, unsigned bits_per_pixel) 220 { 221 unsigned n = width; 222 unsigned k; 223 224 switch(bits_per_pixel) 225 { 226 case 1: k = n; 227 n = n >> 3; 228 if(k & 7) n++; 229 break; 230 231 case 4: k = n; 232 n = n >> 1; 233 if(k & 3) n++; 234 break; 235 236 case 8: 237 break; 238 239 case 16: n *= 2; 240 break; 241 242 case 24: n *= 3; 243 break; 244 245 case 32: n *= 4; 246 break; 247 248 case 48: n *= 6; 249 break; 250 251 case 64: n *= 8; 252 break; 253 254 default: n = 0; 255 break; 256 } 257 return ((n + 3) >> 2) << 2; 258 } 259 260 261 262 263 264 //------------------------------------------------------------------------ draw(HDC h_dc,const RECT * device_rect,const RECT * bmp_rect) const265 void pixel_map::draw(HDC h_dc, const RECT *device_rect, const RECT *bmp_rect) const 266 { 267 if(m_bmp == 0 || m_buf == 0) return; 268 269 unsigned bmp_x = 0; 270 unsigned bmp_y = 0; 271 unsigned bmp_width = m_bmp->bmiHeader.biWidth; 272 unsigned bmp_height = m_bmp->bmiHeader.biHeight; 273 unsigned dvc_x = 0; 274 unsigned dvc_y = 0; 275 unsigned dvc_width = m_bmp->bmiHeader.biWidth; 276 unsigned dvc_height = m_bmp->bmiHeader.biHeight; 277 278 if(bmp_rect) 279 { 280 bmp_x = bmp_rect->left; 281 bmp_y = bmp_rect->top; 282 bmp_width = bmp_rect->right - bmp_rect->left; 283 bmp_height = bmp_rect->bottom - bmp_rect->top; 284 } 285 286 dvc_x = bmp_x; 287 dvc_y = bmp_y; 288 dvc_width = bmp_width; 289 dvc_height = bmp_height; 290 291 if(device_rect) 292 { 293 dvc_x = device_rect->left; 294 dvc_y = device_rect->top; 295 dvc_width = device_rect->right - device_rect->left; 296 dvc_height = device_rect->bottom - device_rect->top; 297 } 298 299 if(dvc_width != bmp_width || dvc_height != bmp_height) 300 { 301 ::SetStretchBltMode(h_dc, COLORONCOLOR); 302 ::StretchDIBits( 303 h_dc, // handle of device context 304 dvc_x, // x-coordinate of upper-left corner of source rect. 305 dvc_y, // y-coordinate of upper-left corner of source rect. 306 dvc_width, // width of source rectangle 307 dvc_height, // height of source rectangle 308 bmp_x, 309 bmp_y, // x, y -coordinates of upper-left corner of dest. rect. 310 bmp_width, // width of destination rectangle 311 bmp_height, // height of destination rectangle 312 m_buf, // address of bitmap bits 313 m_bmp, // address of bitmap data 314 DIB_RGB_COLORS, // usage 315 SRCCOPY // raster operation code 316 ); 317 } 318 else 319 { 320 ::SetDIBitsToDevice( 321 h_dc, // handle to device context 322 dvc_x, // x-coordinate of upper-left corner of 323 dvc_y, // y-coordinate of upper-left corner of 324 dvc_width, // source rectangle width 325 dvc_height, // source rectangle height 326 bmp_x, // x-coordinate of lower-left corner of 327 bmp_y, // y-coordinate of lower-left corner of 328 0, // first scan line in array 329 bmp_height, // number of scan lines 330 m_buf, // address of array with DIB bits 331 m_bmp, // address of structure with bitmap info. 332 DIB_RGB_COLORS // RGB or palette indexes 333 ); 334 } 335 } 336 337 338 //------------------------------------------------------------------------ draw(HDC h_dc,int x,int y,double scale) const339 void pixel_map::draw(HDC h_dc, int x, int y, double scale) const 340 { 341 if(m_bmp == 0 || m_buf == 0) return; 342 343 unsigned width = unsigned(m_bmp->bmiHeader.biWidth * scale); 344 unsigned height = unsigned(m_bmp->bmiHeader.biHeight * scale); 345 RECT rect; 346 rect.left = x; 347 rect.top = y; 348 rect.right = x + width; 349 rect.bottom = y + height; 350 draw(h_dc, &rect); 351 } 352 353 354 355 356 //------------------------------------------------------------------------ blend(HDC h_dc,const RECT * device_rect,const RECT * bmp_rect) const357 void pixel_map::blend(HDC h_dc, const RECT *device_rect, const RECT *bmp_rect) const 358 { 359 #if !defined(AGG_BMP_ALPHA_BLEND) 360 draw(h_dc, device_rect, bmp_rect); 361 return; 362 #else 363 if(m_bpp != 32) 364 { 365 draw(h_dc, device_rect, bmp_rect); 366 return; 367 } 368 369 if(m_bmp == 0 || m_buf == 0) return; 370 371 unsigned bmp_x = 0; 372 unsigned bmp_y = 0; 373 unsigned bmp_width = m_bmp->bmiHeader.biWidth; 374 unsigned bmp_height = m_bmp->bmiHeader.biHeight; 375 unsigned dvc_x = 0; 376 unsigned dvc_y = 0; 377 unsigned dvc_width = m_bmp->bmiHeader.biWidth; 378 unsigned dvc_height = m_bmp->bmiHeader.biHeight; 379 380 if(bmp_rect) 381 { 382 bmp_x = bmp_rect->left; 383 bmp_y = bmp_rect->top; 384 bmp_width = bmp_rect->right - bmp_rect->left; 385 bmp_height = bmp_rect->bottom - bmp_rect->top; 386 } 387 388 dvc_x = bmp_x; 389 dvc_y = bmp_y; 390 dvc_width = bmp_width; 391 dvc_height = bmp_height; 392 393 if(device_rect) 394 { 395 dvc_x = device_rect->left; 396 dvc_y = device_rect->top; 397 dvc_width = device_rect->right - device_rect->left; 398 dvc_height = device_rect->bottom - device_rect->top; 399 } 400 401 HDC mem_dc = ::CreateCompatibleDC(h_dc); 402 void* buf = 0; 403 HBITMAP bmp = ::CreateDIBSection( 404 mem_dc, 405 m_bmp, 406 DIB_RGB_COLORS, 407 &buf, 408 0, 409 0 410 ); 411 memcpy(buf, m_buf, m_bmp->bmiHeader.biSizeImage); 412 413 HBITMAP temp = (HBITMAP)::SelectObject(mem_dc, bmp); 414 415 BLENDFUNCTION blend; 416 blend.BlendOp = AC_SRC_OVER; 417 blend.BlendFlags = 0; 418 419 #if defined(AC_SRC_ALPHA) 420 blend.AlphaFormat = AC_SRC_ALPHA; 421 //#elif defined(AC_SRC_NO_PREMULT_ALPHA) 422 // blend.AlphaFormat = AC_SRC_NO_PREMULT_ALPHA; 423 #else 424 #error "No appropriate constant for alpha format. Check version of wingdi.h, There must be AC_SRC_ALPHA or AC_SRC_NO_PREMULT_ALPHA" 425 #endif 426 427 blend.SourceConstantAlpha = 255; 428 ::AlphaBlend( 429 h_dc, 430 dvc_x, 431 dvc_y, 432 dvc_width, 433 dvc_height, 434 mem_dc, 435 bmp_x, 436 bmp_y, 437 bmp_width, 438 bmp_height, 439 blend 440 ); 441 442 ::SelectObject(mem_dc, temp); 443 ::DeleteObject(bmp); 444 ::DeleteObject(mem_dc); 445 #endif //defined(AGG_BMP_ALPHA_BLEND) 446 } 447 448 449 //------------------------------------------------------------------------ blend(HDC h_dc,int x,int y,double scale) const450 void pixel_map::blend(HDC h_dc, int x, int y, double scale) const 451 { 452 if(m_bmp == 0 || m_buf == 0) return; 453 unsigned width = unsigned(m_bmp->bmiHeader.biWidth * scale); 454 unsigned height = unsigned(m_bmp->bmiHeader.biHeight * scale); 455 RECT rect; 456 rect.left = x; 457 rect.top = y; 458 rect.right = x + width; 459 rect.bottom = y + height; 460 blend(h_dc, &rect); 461 } 462 463 464 //------------------------------------------------------------------------ load_from_bmp(FILE * fd)465 bool pixel_map::load_from_bmp(FILE *fd) 466 { 467 BITMAPFILEHEADER bmf; 468 BITMAPINFO *bmi = 0; 469 unsigned bmp_size; 470 471 fread(&bmf, sizeof(bmf), 1, fd); 472 if(bmf.bfType != 0x4D42) goto bmperr; 473 474 bmp_size = bmf.bfSize - sizeof(BITMAPFILEHEADER); 475 476 bmi = (BITMAPINFO*) new unsigned char [bmp_size]; 477 if(fread(bmi, 1, bmp_size, fd) != bmp_size) goto bmperr; 478 destroy(); 479 m_bpp = bmi->bmiHeader.biBitCount; 480 create_from_bmp(bmi); 481 m_is_internal = 1; 482 return true; 483 484 bmperr: 485 if(bmi) delete [] (unsigned char*) bmi; 486 return false; 487 } 488 489 490 491 //------------------------------------------------------------------------ load_from_bmp(const char * filename)492 bool pixel_map::load_from_bmp(const char *filename) 493 { 494 FILE *fd = fopen(filename, "rb"); 495 bool ret = false; 496 if(fd) 497 { 498 ret = load_from_bmp(fd); 499 fclose(fd); 500 } 501 return ret; 502 } 503 504 505 506 //------------------------------------------------------------------------ save_as_bmp(FILE * fd) const507 bool pixel_map::save_as_bmp(FILE *fd) const 508 { 509 if(m_bmp == 0) return 0; 510 511 BITMAPFILEHEADER bmf; 512 513 bmf.bfType = 0x4D42; 514 bmf.bfOffBits = calc_header_size(m_bmp) + sizeof(bmf); 515 bmf.bfSize = bmf.bfOffBits + m_img_size; 516 bmf.bfReserved1 = 0; 517 bmf.bfReserved2 = 0; 518 519 fwrite(&bmf, sizeof(bmf), 1, fd); 520 fwrite(m_bmp, m_full_size, 1, fd); 521 return true; 522 } 523 524 525 526 //------------------------------------------------------------------------ save_as_bmp(const char * filename) const527 bool pixel_map::save_as_bmp(const char *filename) const 528 { 529 FILE *fd = fopen(filename, "wb"); 530 bool ret = false; 531 if(fd) 532 { 533 ret = save_as_bmp(fd); 534 fclose(fd); 535 } 536 return ret; 537 } 538 539 540 //------------------------------------------------------------------------ buf()541 unsigned char* pixel_map::buf() 542 { 543 return m_buf; 544 } 545 546 //------------------------------------------------------------------------ width() const547 unsigned pixel_map::width() const 548 { 549 return m_bmp->bmiHeader.biWidth; 550 } 551 552 //------------------------------------------------------------------------ height() const553 unsigned pixel_map::height() const 554 { 555 return m_bmp->bmiHeader.biHeight; 556 } 557 558 //------------------------------------------------------------------------ stride() const559 int pixel_map::stride() const 560 { 561 return calc_row_len(m_bmp->bmiHeader.biWidth, 562 m_bmp->bmiHeader.biBitCount); 563 } 564 565 566 //private 567 //------------------------------------------------------------------------ create_from_bmp(BITMAPINFO * bmp)568 void pixel_map::create_from_bmp(BITMAPINFO *bmp) 569 { 570 if(bmp) 571 { 572 m_img_size = calc_row_len(bmp->bmiHeader.biWidth, 573 bmp->bmiHeader.biBitCount) * 574 bmp->bmiHeader.biHeight; 575 576 m_full_size = calc_full_size(bmp); 577 m_bmp = bmp; 578 m_buf = calc_img_ptr(bmp); 579 } 580 } 581 582 583 //private 584 //------------------------------------------------------------------------ create_dib_section_from_args(HDC h_dc,unsigned width,unsigned height,unsigned bits_per_pixel)585 HBITMAP pixel_map::create_dib_section_from_args(HDC h_dc, 586 unsigned width, 587 unsigned height, 588 unsigned bits_per_pixel) 589 { 590 unsigned line_len = calc_row_len(width, bits_per_pixel); 591 unsigned img_size = line_len * height; 592 unsigned rgb_size = calc_palette_size(0, bits_per_pixel) * sizeof(RGBQUAD); 593 unsigned full_size = sizeof(BITMAPINFOHEADER) + rgb_size; 594 595 BITMAPINFO *bmp = (BITMAPINFO *) new unsigned char[full_size]; 596 597 bmp->bmiHeader.biSize = sizeof(BITMAPINFOHEADER); 598 bmp->bmiHeader.biWidth = width; 599 bmp->bmiHeader.biHeight = height; 600 bmp->bmiHeader.biPlanes = 1; 601 bmp->bmiHeader.biBitCount = (unsigned short)bits_per_pixel; 602 bmp->bmiHeader.biCompression = 0; 603 bmp->bmiHeader.biSizeImage = img_size; 604 bmp->bmiHeader.biXPelsPerMeter = 0; 605 bmp->bmiHeader.biYPelsPerMeter = 0; 606 bmp->bmiHeader.biClrUsed = 0; 607 bmp->bmiHeader.biClrImportant = 0; 608 609 void* img_ptr = 0; 610 HBITMAP h_bitmap = ::CreateDIBSection(h_dc, bmp, DIB_RGB_COLORS, &img_ptr, NULL, 0); 611 612 if(img_ptr) 613 { 614 m_img_size = calc_row_len(width, bits_per_pixel) * height; 615 m_full_size = 0; 616 m_bmp = bmp; 617 m_buf = (unsigned char *) img_ptr; 618 } 619 620 return h_bitmap; 621 } 622 } 623 624 625 626