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 case 96: n *= 12; 255 break; 256 257 case 128: n *= 16; 258 break; 259 260 default: n = 0; 261 break; 262 } 263 return ((n + 3) >> 2) << 2; 264 } 265 266 267 268 269 270 //------------------------------------------------------------------------ draw(HDC h_dc,const RECT * device_rect,const RECT * bmp_rect) const271 void pixel_map::draw(HDC h_dc, const RECT *device_rect, const RECT *bmp_rect) const 272 { 273 if(m_bmp == 0 || m_buf == 0) return; 274 275 unsigned bmp_x = 0; 276 unsigned bmp_y = 0; 277 unsigned bmp_width = m_bmp->bmiHeader.biWidth; 278 unsigned bmp_height = m_bmp->bmiHeader.biHeight; 279 unsigned dvc_x = 0; 280 unsigned dvc_y = 0; 281 unsigned dvc_width = m_bmp->bmiHeader.biWidth; 282 unsigned dvc_height = m_bmp->bmiHeader.biHeight; 283 284 if(bmp_rect) 285 { 286 bmp_x = bmp_rect->left; 287 bmp_y = bmp_rect->top; 288 bmp_width = bmp_rect->right - bmp_rect->left; 289 bmp_height = bmp_rect->bottom - bmp_rect->top; 290 } 291 292 dvc_x = bmp_x; 293 dvc_y = bmp_y; 294 dvc_width = bmp_width; 295 dvc_height = bmp_height; 296 297 if(device_rect) 298 { 299 dvc_x = device_rect->left; 300 dvc_y = device_rect->top; 301 dvc_width = device_rect->right - device_rect->left; 302 dvc_height = device_rect->bottom - device_rect->top; 303 } 304 305 if(dvc_width != bmp_width || dvc_height != bmp_height) 306 { 307 ::SetStretchBltMode(h_dc, COLORONCOLOR); 308 ::StretchDIBits( 309 h_dc, // handle of device context 310 dvc_x, // x-coordinate of upper-left corner of source rect. 311 dvc_y, // y-coordinate of upper-left corner of source rect. 312 dvc_width, // width of source rectangle 313 dvc_height, // height of source rectangle 314 bmp_x, 315 bmp_y, // x, y -coordinates of upper-left corner of dest. rect. 316 bmp_width, // width of destination rectangle 317 bmp_height, // height of destination rectangle 318 m_buf, // address of bitmap bits 319 m_bmp, // address of bitmap data 320 DIB_RGB_COLORS, // usage 321 SRCCOPY // raster operation code 322 ); 323 } 324 else 325 { 326 ::SetDIBitsToDevice( 327 h_dc, // handle to device context 328 dvc_x, // x-coordinate of upper-left corner of 329 dvc_y, // y-coordinate of upper-left corner of 330 dvc_width, // source rectangle width 331 dvc_height, // source rectangle height 332 bmp_x, // x-coordinate of lower-left corner of 333 bmp_y, // y-coordinate of lower-left corner of 334 0, // first scan line in array 335 bmp_height, // number of scan lines 336 m_buf, // address of array with DIB bits 337 m_bmp, // address of structure with bitmap info. 338 DIB_RGB_COLORS // RGB or palette indexes 339 ); 340 } 341 } 342 343 344 //------------------------------------------------------------------------ draw(HDC h_dc,int x,int y,double scale) const345 void pixel_map::draw(HDC h_dc, int x, int y, double scale) const 346 { 347 if(m_bmp == 0 || m_buf == 0) return; 348 349 unsigned width = unsigned(m_bmp->bmiHeader.biWidth * scale); 350 unsigned height = unsigned(m_bmp->bmiHeader.biHeight * scale); 351 RECT rect; 352 rect.left = x; 353 rect.top = y; 354 rect.right = x + width; 355 rect.bottom = y + height; 356 draw(h_dc, &rect); 357 } 358 359 360 361 362 //------------------------------------------------------------------------ blend(HDC h_dc,const RECT * device_rect,const RECT * bmp_rect) const363 void pixel_map::blend(HDC h_dc, const RECT *device_rect, const RECT *bmp_rect) const 364 { 365 #if !defined(AGG_BMP_ALPHA_BLEND) 366 draw(h_dc, device_rect, bmp_rect); 367 return; 368 #else 369 if(m_bpp != 32) 370 { 371 draw(h_dc, device_rect, bmp_rect); 372 return; 373 } 374 375 if(m_bmp == 0 || m_buf == 0) return; 376 377 unsigned bmp_x = 0; 378 unsigned bmp_y = 0; 379 unsigned bmp_width = m_bmp->bmiHeader.biWidth; 380 unsigned bmp_height = m_bmp->bmiHeader.biHeight; 381 unsigned dvc_x = 0; 382 unsigned dvc_y = 0; 383 unsigned dvc_width = m_bmp->bmiHeader.biWidth; 384 unsigned dvc_height = m_bmp->bmiHeader.biHeight; 385 386 if(bmp_rect) 387 { 388 bmp_x = bmp_rect->left; 389 bmp_y = bmp_rect->top; 390 bmp_width = bmp_rect->right - bmp_rect->left; 391 bmp_height = bmp_rect->bottom - bmp_rect->top; 392 } 393 394 dvc_x = bmp_x; 395 dvc_y = bmp_y; 396 dvc_width = bmp_width; 397 dvc_height = bmp_height; 398 399 if(device_rect) 400 { 401 dvc_x = device_rect->left; 402 dvc_y = device_rect->top; 403 dvc_width = device_rect->right - device_rect->left; 404 dvc_height = device_rect->bottom - device_rect->top; 405 } 406 407 HDC mem_dc = ::CreateCompatibleDC(h_dc); 408 void* buf = 0; 409 HBITMAP bmp = ::CreateDIBSection( 410 mem_dc, 411 m_bmp, 412 DIB_RGB_COLORS, 413 &buf, 414 0, 415 0 416 ); 417 memcpy(buf, m_buf, m_bmp->bmiHeader.biSizeImage); 418 419 HBITMAP temp = (HBITMAP)::SelectObject(mem_dc, bmp); 420 421 BLENDFUNCTION blend; 422 blend.BlendOp = AC_SRC_OVER; 423 blend.BlendFlags = 0; 424 425 #if defined(AC_SRC_ALPHA) 426 blend.AlphaFormat = AC_SRC_ALPHA; 427 //#elif defined(AC_SRC_NO_PREMULT_ALPHA) 428 // blend.AlphaFormat = AC_SRC_NO_PREMULT_ALPHA; 429 #else 430 #error "No appropriate constant for alpha format. Check version of wingdi.h, There must be AC_SRC_ALPHA or AC_SRC_NO_PREMULT_ALPHA" 431 #endif 432 433 blend.SourceConstantAlpha = 255; 434 ::AlphaBlend( 435 h_dc, 436 dvc_x, 437 dvc_y, 438 dvc_width, 439 dvc_height, 440 mem_dc, 441 bmp_x, 442 bmp_y, 443 bmp_width, 444 bmp_height, 445 blend 446 ); 447 448 ::SelectObject(mem_dc, temp); 449 ::DeleteObject(bmp); 450 ::DeleteObject(mem_dc); 451 #endif //defined(AGG_BMP_ALPHA_BLEND) 452 } 453 454 455 //------------------------------------------------------------------------ blend(HDC h_dc,int x,int y,double scale) const456 void pixel_map::blend(HDC h_dc, int x, int y, double scale) const 457 { 458 if(m_bmp == 0 || m_buf == 0) return; 459 unsigned width = unsigned(m_bmp->bmiHeader.biWidth * scale); 460 unsigned height = unsigned(m_bmp->bmiHeader.biHeight * scale); 461 RECT rect; 462 rect.left = x; 463 rect.top = y; 464 rect.right = x + width; 465 rect.bottom = y + height; 466 blend(h_dc, &rect); 467 } 468 469 470 //------------------------------------------------------------------------ load_from_bmp(FILE * fd)471 bool pixel_map::load_from_bmp(FILE *fd) 472 { 473 BITMAPFILEHEADER bmf; 474 BITMAPINFO *bmi = 0; 475 unsigned bmp_size; 476 477 fread(&bmf, sizeof(bmf), 1, fd); 478 if(bmf.bfType != 0x4D42) goto bmperr; 479 480 bmp_size = bmf.bfSize - sizeof(BITMAPFILEHEADER); 481 482 bmi = (BITMAPINFO*) new unsigned char [bmp_size]; 483 if(fread(bmi, 1, bmp_size, fd) != bmp_size) goto bmperr; 484 destroy(); 485 m_bpp = bmi->bmiHeader.biBitCount; 486 create_from_bmp(bmi); 487 m_is_internal = 1; 488 return true; 489 490 bmperr: 491 if(bmi) delete [] (unsigned char*) bmi; 492 return false; 493 } 494 495 496 497 //------------------------------------------------------------------------ load_from_bmp(const char * filename)498 bool pixel_map::load_from_bmp(const char *filename) 499 { 500 FILE *fd = fopen(filename, "rb"); 501 bool ret = false; 502 if(fd) 503 { 504 ret = load_from_bmp(fd); 505 fclose(fd); 506 } 507 return ret; 508 } 509 510 511 512 //------------------------------------------------------------------------ save_as_bmp(FILE * fd) const513 bool pixel_map::save_as_bmp(FILE *fd) const 514 { 515 if(m_bmp == 0) return 0; 516 517 BITMAPFILEHEADER bmf; 518 519 bmf.bfType = 0x4D42; 520 bmf.bfOffBits = calc_header_size(m_bmp) + sizeof(bmf); 521 bmf.bfSize = bmf.bfOffBits + m_img_size; 522 bmf.bfReserved1 = 0; 523 bmf.bfReserved2 = 0; 524 525 fwrite(&bmf, sizeof(bmf), 1, fd); 526 fwrite(m_bmp, m_full_size, 1, fd); 527 return true; 528 } 529 530 531 532 //------------------------------------------------------------------------ save_as_bmp(const char * filename) const533 bool pixel_map::save_as_bmp(const char *filename) const 534 { 535 FILE *fd = fopen(filename, "wb"); 536 bool ret = false; 537 if(fd) 538 { 539 ret = save_as_bmp(fd); 540 fclose(fd); 541 } 542 return ret; 543 } 544 545 546 //------------------------------------------------------------------------ buf()547 unsigned char* pixel_map::buf() 548 { 549 return m_buf; 550 } 551 552 //------------------------------------------------------------------------ width() const553 unsigned pixel_map::width() const 554 { 555 return m_bmp->bmiHeader.biWidth; 556 } 557 558 //------------------------------------------------------------------------ height() const559 unsigned pixel_map::height() const 560 { 561 return m_bmp->bmiHeader.biHeight; 562 } 563 564 //------------------------------------------------------------------------ stride() const565 int pixel_map::stride() const 566 { 567 return calc_row_len(m_bmp->bmiHeader.biWidth, 568 m_bmp->bmiHeader.biBitCount); 569 } 570 571 572 //private 573 //------------------------------------------------------------------------ create_from_bmp(BITMAPINFO * bmp)574 void pixel_map::create_from_bmp(BITMAPINFO *bmp) 575 { 576 if(bmp) 577 { 578 m_img_size = calc_row_len(bmp->bmiHeader.biWidth, 579 bmp->bmiHeader.biBitCount) * 580 bmp->bmiHeader.biHeight; 581 582 m_full_size = calc_full_size(bmp); 583 m_bmp = bmp; 584 m_buf = calc_img_ptr(bmp); 585 } 586 } 587 588 589 //private 590 //------------------------------------------------------------------------ create_dib_section_from_args(HDC h_dc,unsigned width,unsigned height,unsigned bits_per_pixel)591 HBITMAP pixel_map::create_dib_section_from_args(HDC h_dc, 592 unsigned width, 593 unsigned height, 594 unsigned bits_per_pixel) 595 { 596 unsigned line_len = calc_row_len(width, bits_per_pixel); 597 unsigned img_size = line_len * height; 598 unsigned rgb_size = calc_palette_size(0, bits_per_pixel) * sizeof(RGBQUAD); 599 unsigned full_size = sizeof(BITMAPINFOHEADER) + rgb_size; 600 601 BITMAPINFO *bmp = (BITMAPINFO *) new unsigned char[full_size]; 602 603 bmp->bmiHeader.biSize = sizeof(BITMAPINFOHEADER); 604 bmp->bmiHeader.biWidth = width; 605 bmp->bmiHeader.biHeight = height; 606 bmp->bmiHeader.biPlanes = 1; 607 bmp->bmiHeader.biBitCount = (unsigned short)bits_per_pixel; 608 bmp->bmiHeader.biCompression = 0; 609 bmp->bmiHeader.biSizeImage = img_size; 610 bmp->bmiHeader.biXPelsPerMeter = 0; 611 bmp->bmiHeader.biYPelsPerMeter = 0; 612 bmp->bmiHeader.biClrUsed = 0; 613 bmp->bmiHeader.biClrImportant = 0; 614 615 void* img_ptr = 0; 616 HBITMAP h_bitmap = ::CreateDIBSection(h_dc, bmp, DIB_RGB_COLORS, &img_ptr, NULL, 0); 617 618 if(img_ptr) 619 { 620 m_img_size = calc_row_len(width, bits_per_pixel) * height; 621 m_full_size = 0; 622 m_bmp = bmp; 623 m_buf = (unsigned char *) img_ptr; 624 } 625 626 return h_bitmap; 627 } 628 } 629 630 631 632