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