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