]> Creatis software - clitk.git/blob - utilities/CxImage/ximawnd.cpp
Debug RTStruct conversion with empty struc
[clitk.git] / utilities / CxImage / ximawnd.cpp
1 // xImaWnd.cpp : Windows functions
2 /* 07/08/2001 v1.00 - Davide Pizzolato - www.xdp.it
3  * CxImage version 6.0.0 02/Feb/2008
4  */
5
6 #include "ximage.h"
7
8 #include "ximaiter.h" 
9 #include "ximabmp.h"
10
11 ////////////////////////////////////////////////////////////////////////////////
12 #if defined (_WIN32_WCE)
13
14 #ifndef DEFAULT_GUI_FONT
15 #define DEFAULT_GUI_FONT 17
16 #endif
17
18 #ifndef PROOF_QUALITY
19 #define PROOF_QUALITY 2
20 #endif
21
22 struct DIBINFO : public BITMAPINFO
23 {
24         RGBQUAD    arColors[255];    // Color table info - adds an extra 255 entries to palette
25         operator LPBITMAPINFO()          { return (LPBITMAPINFO) this; }
26         operator LPBITMAPINFOHEADER()    { return &bmiHeader;          }
27         RGBQUAD* ColorTable()            { return bmiColors;           }
28 };
29
30 int BytesPerLine(int nWidth, int nBitsPerPixel)
31 {
32     return ( (nWidth * nBitsPerPixel + 31) & (~31) ) / 8;
33 }
34
35 int NumColorEntries(int nBitsPerPixel, int nCompression, DWORD biClrUsed)
36 {
37         int nColors = 0;
38         switch (nBitsPerPixel)
39         {
40         case 1:
41                 nColors = 2;  break;
42         case 2:
43                 nColors = 4;  break;   // winCE only
44         case 4:
45                 nColors = 16; break;
46         case 8:
47                 nColors =256; break;
48         case 24:
49                 nColors = 0;  break;
50         case 16:
51         case 32:
52                 nColors = 3;  break; // I've found that PocketPCs need this regardless of BI_RGB or BI_BITFIELDS
53         default:
54                 ASSERT(FALSE);
55         }
56         // If biClrUsed is provided, and it is a legal value, use it
57         if (biClrUsed > 0 && biClrUsed <= (DWORD)nColors)
58                 return biClrUsed;
59         
60         return nColors;
61 }
62
63 int GetDIBits(
64   HDC hdc,           // handle to DC
65   HBITMAP hbmp,      // handle to bitmap
66   UINT uStartScan,   // first scan line to set
67   UINT cScanLines,   // number of scan lines to copy
68   LPVOID lpvBits,    // array for bitmap bits
69   LPBITMAPINFO lpbi, // bitmap data buffer
70   UINT uUsage        // RGB or palette index
71 )
72 {
73         UINT    iColorTableSize = 0;
74
75         if (!hbmp)
76                 return 0;
77
78         // Get dimensions of bitmap
79         BITMAP bm;
80         if (!::GetObject(hbmp, sizeof(bm),(LPVOID)&bm))
81                 return 0;
82
83         //3. Creating new bitmap and receive pointer to it's bits.
84         HBITMAP hTargetBitmap;
85         void *pBuffer;
86         
87         //3.1 Initilize DIBINFO structure
88         DIBINFO  dibInfo;
89         dibInfo.bmiHeader.biBitCount = 24;
90         dibInfo.bmiHeader.biClrImportant = 0;
91         dibInfo.bmiHeader.biClrUsed = 0;
92         dibInfo.bmiHeader.biCompression = 0;
93         dibInfo.bmiHeader.biHeight = bm.bmHeight;
94         dibInfo.bmiHeader.biPlanes = 1;
95         dibInfo.bmiHeader.biSize = 40;
96         dibInfo.bmiHeader.biSizeImage = bm.bmHeight*BytesPerLine(bm.bmWidth,24);
97         dibInfo.bmiHeader.biWidth = bm.bmWidth;
98         dibInfo.bmiHeader.biXPelsPerMeter = 3780;
99         dibInfo.bmiHeader.biYPelsPerMeter = 3780;
100         dibInfo.bmiColors[0].rgbBlue = 0;
101         dibInfo.bmiColors[0].rgbGreen = 0;
102         dibInfo.bmiColors[0].rgbRed = 0;
103         dibInfo.bmiColors[0].rgbReserved = 0;
104
105         //3.2 Create bitmap and receive pointer to points into pBuffer
106         HDC hDC = ::GetDC(NULL);
107         ASSERT(hDC);
108         hTargetBitmap = CreateDIBSection(
109                 hDC,
110                 (const BITMAPINFO*)dibInfo,
111                 DIB_RGB_COLORS,
112                 (void**)&pBuffer,
113                 NULL,
114                 0);
115
116         ::ReleaseDC(NULL, hDC);
117
118         //4. Copy source bitmap into the target bitmap.
119
120         //4.1 Create 2 device contexts
121         HDC memDc = CreateCompatibleDC(NULL);
122         if (!memDc) {
123                 ASSERT(FALSE);
124         }
125         
126         HDC targetDc = CreateCompatibleDC(NULL);
127         if (!targetDc) {
128                 ASSERT(FALSE);
129         }
130
131         //4.2 Select source bitmap into one DC, target into another
132         HBITMAP hOldBitmap1 = (HBITMAP)::SelectObject(memDc, hbmp);
133         HBITMAP hOldBitmap2 = (HBITMAP)::SelectObject(targetDc, hTargetBitmap);
134
135         //4.3 Copy source bitmap into the target one
136         BitBlt(targetDc, 0, 0, bm.bmWidth, bm.bmHeight, memDc, 0, 0, SRCCOPY);
137
138         //4.4 Restore device contexts
139         ::SelectObject(memDc, hOldBitmap1);
140         ::SelectObject(targetDc, hOldBitmap2);
141         DeleteDC(memDc);
142         DeleteDC(targetDc);
143
144         //Here we can bitmap bits: pBuffer. Note:
145         // 1. pBuffer contains 3 bytes per point
146         // 2. Lines ane from the bottom to the top!
147         // 3. Points in the line are from the left to the right
148         // 4. Bytes in one point are BGR (blue, green, red) not RGB
149         // 5. Don't delete pBuffer, it will be automatically deleted
150         //    when delete hTargetBitmap
151         lpvBits = pBuffer;
152
153         DeleteObject(hbmp);
154         //DeleteObject(hTargetBitmap);
155
156         return 1;
157 }
158 #endif 
159
160 ////////////////////////////////////////////////////////////////////////////////
161 #if CXIMAGE_SUPPORT_WINDOWS
162 ////////////////////////////////////////////////////////////////////////////////
163 long CxImage::Blt(HDC pDC, long x, long y)
164 {
165         if((pDib==0)||(pDC==0)||(!info.bEnabled)) return 0;
166
167     HBRUSH brImage = CreateDIBPatternBrushPt(pDib, DIB_RGB_COLORS);
168     POINT pt;
169     SetBrushOrgEx(pDC,x,y,&pt); //<RT>
170     HBRUSH brOld = (HBRUSH) SelectObject(pDC, brImage);
171     PatBlt(pDC, x, y, head.biWidth, head.biHeight, PATCOPY);
172     SelectObject(pDC, brOld);
173     SetBrushOrgEx(pDC,pt.x,pt.y,NULL);
174     DeleteObject(brImage);
175     return 1;
176 }
177 ////////////////////////////////////////////////////////////////////////////////
178 /**
179  * Transfer the image in a global bitmap handle (clipboard copy)
180  */
181 HANDLE CxImage::CopyToHandle()
182 {
183         HANDLE hMem=NULL;
184         if (pDib){
185                 hMem= GlobalAlloc(GHND, GetSize());
186                 if (hMem){
187                         BYTE* pDst=(BYTE*)GlobalLock(hMem);
188                         if (pDst){
189                                 memcpy(pDst,pDib,GetSize());
190                         }
191                         GlobalUnlock(hMem);
192                 }
193         }
194         return hMem;
195 }
196 ////////////////////////////////////////////////////////////////////////////////
197 /**
198  * Global object (clipboard paste) constructor
199  * \param hMem: source bitmap object, the clipboard format must be CF_DIB
200  * \return true if everything is ok
201  */
202 bool CxImage::CreateFromHANDLE(HANDLE hMem)
203 {
204         if (!Destroy())
205                 return false;
206
207         DWORD dwSize = GlobalSize(hMem);
208         if (!dwSize) return false;
209
210         BYTE *lpVoid;                                           //pointer to the bitmap
211         lpVoid = (BYTE *)GlobalLock(hMem);
212         BITMAPINFOHEADER *pHead;                        //pointer to the bitmap header
213         pHead = (BITMAPINFOHEADER *)lpVoid;
214         if (lpVoid){
215
216                 //CxMemFile hFile(lpVoid,dwSize);
217
218                 //copy the bitmap header
219                 memcpy(&head,pHead,sizeof(BITMAPINFOHEADER));
220                 //check if it's a top-down bitmap
221                 bool bTopDownDib = head.biHeight<0;
222                 if (bTopDownDib) head.biHeight=-head.biHeight;
223                 //create the image
224                 if(!Create(head.biWidth,head.biHeight,head.biBitCount)){
225                         GlobalUnlock(lpVoid);
226                         return false;
227                 }
228                 //preserve DPI
229                 SetXDPI((long)floor(head.biXPelsPerMeter * 254.0 / 10000.0 + 0.5));
230                 SetYDPI((long)floor(head.biYPelsPerMeter * 254.0 / 10000.0 + 0.5));
231
232                 /*//copy the pixels (old way)
233                 if((pHead->biCompression != BI_RGB) || (pHead->biBitCount == 32)){ //<Jörgen Alfredsson>
234                         // BITFIELD case
235                         // set the internal header in the dib
236                         memcpy(pDib,&head,sizeof(head));
237                         // get the bitfield masks
238                         DWORD bf[3];
239                         memcpy(bf,lpVoid+pHead->biSize,12);
240                         // transform into RGB
241                         Bitfield2RGB(lpVoid+pHead->biSize+12,bf[0],bf[1],bf[2],(BYTE)pHead->biBitCount);
242                 } else { //normal bitmap
243                         memcpy(pDib,lpVoid,GetSize());
244                 }*/
245
246                 // <Michael Gandyra>
247                 // fill in color map
248                 bool bIsOldBmp = (head.biSize == sizeof(BITMAPCOREHEADER));
249                 RGBQUAD *pRgb = GetPalette();
250                 if (pRgb) {
251                         // number of colors to fill in
252                         int nColors = DibNumColors(pHead);
253                         if (bIsOldBmp) {
254                                 /* get pointer to BITMAPCOREINFO (old style 1.x) */
255                                 LPBITMAPCOREINFO lpbmc = (LPBITMAPCOREINFO)lpVoid;
256                                 for (int i = nColors - 1; i >= 0; i--) {
257                                         pRgb[i].rgbRed      = lpbmc->bmciColors[i].rgbtRed;
258                                         pRgb[i].rgbGreen    = lpbmc->bmciColors[i].rgbtGreen;
259                                         pRgb[i].rgbBlue     = lpbmc->bmciColors[i].rgbtBlue;
260                                         pRgb[i].rgbReserved = (BYTE)0;
261                                 }
262                         } else {
263                                 /* get pointer to BITMAPINFO (new style 3.x) */
264                                 LPBITMAPINFO lpbmi = (LPBITMAPINFO)lpVoid;
265                                 for (int i = nColors - 1; i >= 0; i--) {
266                                         pRgb[i].rgbRed      = lpbmi->bmiColors[i].rgbRed;
267                                         pRgb[i].rgbGreen    = lpbmi->bmiColors[i].rgbGreen;
268                                         pRgb[i].rgbBlue     = lpbmi->bmiColors[i].rgbBlue;
269                                         pRgb[i].rgbReserved = (BYTE)0;
270                                 }
271                         }
272                 }
273
274                 // <Michael Gandyra>
275                 DWORD dwCompression = pHead->biCompression;
276                 // compressed bitmap ?
277                 if(dwCompression!=BI_RGB || pHead->biBitCount==32 || pHead->biBitCount ==16) {
278                         // get the bitmap bits
279                         LPSTR lpDIBBits = (LPSTR)((BYTE*)pHead + *(DWORD*)pHead + (WORD)(GetNumColors() * sizeof(RGBQUAD)));
280                         // decode and copy them to our image
281                         switch (pHead->biBitCount) {
282                         case 32 :
283                                 {
284                                         // BITFIELD case
285                                         if (dwCompression == BI_BITFIELDS || dwCompression == BI_RGB) {
286                                                 // get the bitfield masks
287                                                 DWORD bf[3];
288                                                 memcpy(bf,lpVoid+pHead->biSize,12);
289                                                 // transform into RGB
290                                                 Bitfield2RGB(lpVoid+pHead->biSize+12,bf[0],bf[1],bf[2],(BYTE)pHead->biBitCount);
291                                         } else {
292                                                 // "unknown compression";
293                                                 GlobalUnlock(lpVoid);
294                                                 return false;
295                                         }
296                                 }
297                                 break;
298                         case 16 :
299                                 {
300                                         // get the bitfield masks
301                                         long offset=0;
302                                         DWORD bf[3];
303                                         if (dwCompression == BI_BITFIELDS) {
304                                                 memcpy(bf,lpVoid+pHead->biSize,12);
305                                                 offset= 12;
306                                         } else {
307                                                 bf[0] = 0x7C00;
308                                                 bf[1] = 0x3E0;
309                                                 bf[2] = 0x1F; // RGB555
310                                         }
311                                         // copy the pixels
312                                         memcpy(info.pImage, lpDIBBits + offset, head.biHeight*((head.biWidth+1)/2)*4);
313                                         // transform into RGB
314                                         Bitfield2RGB(info.pImage, bf[0], bf[1], bf[2], 16);
315                                 }
316                                 break;
317                         case 8 :
318                         case 4 :
319                         case 1 :
320                                 {
321                                         switch (dwCompression) {
322                                         case BI_RLE4:
323                                                 {
324                                                         BYTE status_byte = 0;
325                                                         BYTE second_byte = 0;
326                                                         int scanline = 0;
327                                                         int bits = 0;
328                                                         BOOL low_nibble = FALSE;
329                                                         CImageIterator iter(this);
330
331                                                         for (BOOL bContinue = TRUE; bContinue; ) {
332                                                                 status_byte = *(lpDIBBits++);
333                                                                 switch (status_byte) {
334                                                                 case RLE_COMMAND :
335                                                                         status_byte = *(lpDIBBits++);
336                                                                         switch (status_byte) {
337                                                                         case RLE_ENDOFLINE :
338                                                                                 bits = 0;
339                                                                                 scanline++;
340                                                                                 low_nibble = FALSE;
341                                                                                 break;
342                                                                         case RLE_ENDOFBITMAP :
343                                                                                 bContinue = FALSE;
344                                                                                 break;
345                                                                         case RLE_DELTA :
346                                                                                 {
347                                                                                         // read the delta values
348                                                                                         BYTE delta_x;
349                                                                                         BYTE delta_y;
350                                                                                         delta_x = *(lpDIBBits++);
351                                                                                         delta_y = *(lpDIBBits++);
352                                                                                         // apply them
353                                                                                         bits       += delta_x / 2;
354                                                                                         scanline   += delta_y;
355                                                                                         break;
356                                                                                 }
357                                                                         default :
358                                                                                 second_byte = *(lpDIBBits++);
359                                                                                 BYTE* sline = iter.GetRow(scanline);
360                                                                                 for (int i = 0; i < status_byte; i++) {
361                                                                                         if ((BYTE*)(sline+bits) < (BYTE*)(info.pImage+head.biSizeImage)){
362                                                                                                 if (low_nibble) {
363                                                                                                         if (i&1)
364                                                                                                                 *(sline + bits) |= (second_byte & 0x0f);
365                                                                                                         else
366                                                                                                                 *(sline + bits) |= (second_byte & 0xf0)>>4;
367                                                                                                         bits++;
368                                                                                                 } else {
369                                                                                                         if (i&1)
370                                                                                                                 *(sline + bits) = (BYTE)(second_byte & 0x0f)<<4;
371                                                                                                         else
372                                                                                                                 *(sline + bits) = (BYTE)(second_byte & 0xf0);
373                                                                                                 }
374                                                                                         }
375
376                                                                                         if ((i & 1) && (i != (status_byte - 1)))
377                                                                                                 second_byte = *(lpDIBBits++);
378
379                                                                                         low_nibble = !low_nibble;
380                                                                                 }
381                                                                                 if ((((status_byte+1) >> 1) & 1 ) == 1)
382                                                                                         second_byte = *(lpDIBBits++);                                                                                           
383                                                                                 break;
384                                                                         };
385                                                                         break;
386                                                                         default :
387                                                                         {
388                                                                                 BYTE* sline = iter.GetRow(scanline);
389                                                                                 second_byte = *(lpDIBBits++);
390                                                                                 for (unsigned i = 0; i < status_byte; i++) {
391                                                                                         if ((BYTE*)(sline+bits) < (BYTE*)(info.pImage+head.biSizeImage)){
392                                                                                                 if (low_nibble) {
393                                                                                                         if (i&1)
394                                                                                                                 *(sline + bits) |= (second_byte & 0x0f);
395                                                                                                         else
396                                                                                                                 *(sline + bits) |= (second_byte & 0xf0)>>4;
397                                                                                                         bits++;
398                                                                                                 } else {
399                                                                                                         if (i&1)
400                                                                                                                 *(sline + bits) = (BYTE)(second_byte & 0x0f)<<4;
401                                                                                                         else
402                                                                                                                 *(sline + bits) = (BYTE)(second_byte & 0xf0);
403                                                                                                 }
404                                                                                         }
405                                                                                         low_nibble = !low_nibble;
406                                                                                 }
407                                                                         }
408                                                                         break;
409                                                                 };
410                                                         }
411                                                 }
412                                                 break;
413                                         case BI_RLE8 :
414                                                 {
415                                                         BYTE status_byte = 0;
416                                                         BYTE second_byte = 0;
417                                                         int scanline = 0;
418                                                         int bits = 0;
419                                                         CImageIterator iter(this);
420
421                                                         for (BOOL bContinue = TRUE; bContinue; ) {
422                                                                 status_byte = *(lpDIBBits++);
423                                                                 if (status_byte==RLE_COMMAND) {
424                                                                         status_byte = *(lpDIBBits++);
425                                                                         switch (status_byte) {
426                                                                         case RLE_ENDOFLINE :
427                                                                                 bits = 0;
428                                                                                 scanline++;
429                                                                                 break;
430                                                                         case RLE_ENDOFBITMAP :
431                                                                                 bContinue = FALSE;
432                                                                                 break;
433                                                                         case RLE_DELTA :
434                                                                                 {
435                                                                                         // read the delta values
436                                                                                         BYTE delta_x;
437                                                                                         BYTE delta_y;
438                                                                                         delta_x = *(lpDIBBits++);
439                                                                                         delta_y = *(lpDIBBits++);
440                                                                                         // apply them
441                                                                                         bits     += delta_x;
442                                                                                         scanline += delta_y;
443                                                                                 }
444                                                                                 break;
445                                                                         default :
446                                                                                 int nNumBytes = sizeof(BYTE) * status_byte;
447                                                                                 memcpy((void *)(iter.GetRow(scanline) + bits), lpDIBBits, nNumBytes);
448                                                                                 lpDIBBits += nNumBytes;
449                                                                                 // align run length to even number of bytes 
450                                                                                 if ((status_byte & 1) == 1)
451                                                                                         second_byte = *(lpDIBBits++);
452                                                                                 bits += status_byte;
453                                                                                 break;
454                                                                         };
455                                                                 } else {
456                                                                         BYTE *sline = iter.GetRow(scanline);
457                                                                         second_byte = *(lpDIBBits++);
458                                                                         for (unsigned i = 0; i < status_byte; i++) {
459                                                                                 if ((DWORD)bits<info.dwEffWidth){
460                                                                                         *(sline + bits) = second_byte;
461                                                                                         bits++;
462                                                                                 } else {
463                                                                                         bContinue = FALSE; //don't delete: we are in memory, it is not as with files
464                                                                                         break;
465                                                                                 }
466                                                                         }
467                                                                 }
468                                                         }
469                                                 }
470                                                 break;
471                                         default :
472                                                 {
473                                                         // "compression type not supported";
474                                                         GlobalUnlock(lpVoid);
475                                                         return false;
476                                                 }
477                                         }
478                                 }
479                         }
480                 } else {
481                         //normal bitmap (not compressed)
482                         memcpy(pDib,lpVoid,GetSize());
483                 }
484
485                 GlobalUnlock(lpVoid);
486
487                 if (bTopDownDib) Flip();
488
489                 return true;
490         }
491         return false;
492 }
493 ////////////////////////////////////////////////////////////////////////////////
494 /**
495  * Transfer the image in a  bitmap handle
496  * \param hdc: target device context (the screen, usually)
497  * \return bitmap handle, or NULL if an error occurs.
498  */
499 HBITMAP CxImage::MakeBitmap(HDC hdc)
500 {
501         if (!pDib)
502                 return NULL;
503
504         if (!hdc){
505                 // this call to CreateBitmap doesn't create a DIB <jaslet>
506                 // // Create a device-independent bitmap <CSC>
507                 //  return CreateBitmap(head.biWidth,head.biHeight,     1, head.biBitCount, GetBits());
508                 // use instead this code
509                 HDC hMemDC = CreateCompatibleDC(NULL);
510                 LPVOID pBit32;
511                 HBITMAP bmp = CreateDIBSection(hMemDC,(LPBITMAPINFO)pDib,DIB_RGB_COLORS, &pBit32, NULL, 0);
512                 if (pBit32) memcpy(pBit32, GetBits(), head.biSizeImage);
513                 DeleteDC(hMemDC);
514                 return bmp;
515         }
516
517         // this single line seems to work very well
518         //HBITMAP bmp = CreateDIBitmap(hdc, (LPBITMAPINFOHEADER)pDib, CBM_INIT,
519         //      GetBits(), (LPBITMAPINFO)pDib, DIB_RGB_COLORS);
520         // this alternative works also with _WIN32_WCE
521         LPVOID pBit32;
522         HBITMAP bmp = CreateDIBSection(hdc, (LPBITMAPINFO)pDib, DIB_RGB_COLORS, &pBit32, NULL, 0);
523         if (pBit32) memcpy(pBit32, GetBits(), head.biSizeImage);
524
525         return bmp;
526 }
527 ////////////////////////////////////////////////////////////////////////////////
528 /**
529  * Bitmap resource constructor
530  * \param hbmp : bitmap resource handle
531  * \param hpal : (optional) palette, useful for 8bpp DC 
532  * \return true if everything is ok
533  */
534 bool CxImage::CreateFromHBITMAP(HBITMAP hbmp, HPALETTE hpal)
535 {
536         if (!Destroy())
537                 return false;
538
539         if (hbmp) { 
540         BITMAP bm;
541                 // get informations about the bitmap
542         GetObject(hbmp, sizeof(BITMAP), (LPSTR) &bm);
543                 // create the image
544         if (!Create(bm.bmWidth, bm.bmHeight, bm.bmBitsPixel, 0))
545                         return false;
546                 // create a device context for the bitmap
547         HDC dc = ::GetDC(NULL);
548                 if (!dc)
549                         return false;
550
551                 if (hpal){
552                         SelectObject(dc,hpal); //the palette you should get from the user or have a stock one
553                         RealizePalette(dc);
554                 }
555
556                 // copy the pixels
557         if (GetDIBits(dc, hbmp, 0, head.biHeight, info.pImage,
558                         (LPBITMAPINFO)pDib, DIB_RGB_COLORS) == 0){ //replace &head with pDib <Wil Stark>
559             strcpy(info.szLastError,"GetDIBits failed");
560                         ::ReleaseDC(NULL, dc);
561                         return false;
562         }
563         ::ReleaseDC(NULL, dc);
564                 return true;
565     }
566         return false;
567 }
568 ////////////////////////////////////////////////////////////////////////////////
569 /**
570  * icon resource constructor
571  * \param hico : icon resource handle
572  * \return true if everything is ok
573  * \author []; changes [Arlen Albert Keshabian]
574  */
575 #if !defined (_WIN32_WCE)
576 bool CxImage::CreateFromHICON(HICON hico)
577 {
578         if (!Destroy() || !hico)
579                 return false;
580
581         bool l_bResult = true;
582
583         ICONINFO iinfo;
584         GetIconInfo(hico,&iinfo);
585
586         BITMAP l_Bitmap;
587         GetObject(iinfo.hbmColor, sizeof(BITMAP), &l_Bitmap);
588
589         if(l_Bitmap.bmBitsPixel == 32)
590         {
591                 BITMAPINFO l_BitmapInfo;
592                 l_BitmapInfo.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
593                 l_BitmapInfo.bmiHeader.biWidth = l_Bitmap.bmWidth;
594                 l_BitmapInfo.bmiHeader.biHeight = l_Bitmap.bmHeight;
595                 l_BitmapInfo.bmiHeader.biPlanes = l_Bitmap.bmPlanes;
596                 l_BitmapInfo.bmiHeader.biBitCount = l_Bitmap.bmBitsPixel;
597                 l_BitmapInfo.bmiHeader.biCompression = BI_RGB;
598
599                 RGBQUAD *l_pRawBytes = new RGBQUAD[l_Bitmap.bmWidth * l_Bitmap.bmHeight];
600
601                 HDC dc = ::GetDC(NULL);
602
603                 if(dc)
604                 {
605                         if(GetDIBits(dc, iinfo.hbmColor, 0, l_Bitmap.bmHeight, l_pRawBytes, &l_BitmapInfo, DIB_RGB_COLORS))
606                                 l_bResult = CreateFromArray((BYTE*)l_pRawBytes, l_Bitmap.bmWidth, l_Bitmap.bmHeight, l_Bitmap.bmBitsPixel, l_Bitmap.bmWidthBytes, false);
607                         else
608                                 l_bResult = false;
609
610                         ::ReleaseDC(NULL, dc);
611                 }
612                 else
613                         l_bResult = false;
614
615                 delete [] l_pRawBytes;
616         }
617         else
618         {
619                 l_bResult = CreateFromHBITMAP(iinfo.hbmColor);
620 #if CXIMAGE_SUPPORT_ALPHA
621                 if(l_bResult)
622                 {
623                         CxImage mask;
624                         mask.CreateFromHBITMAP(iinfo.hbmMask);
625                         mask.GrayScale();
626                         mask.Negative();
627                         AlphaSet(mask);
628                 }
629 #endif
630         }
631
632         DeleteObject(iinfo.hbmColor); //<Sims>
633         DeleteObject(iinfo.hbmMask);  //<Sims>
634         
635         return l_bResult;
636 }
637 #endif //_WIN32_WCE
638 ////////////////////////////////////////////////////////////////////////////////
639 long CxImage::Draw(HDC hdc, const RECT& rect, RECT* pClipRect, bool bSmooth)
640 {
641         return Draw(hdc, rect.left, rect.top, rect.right - rect.left, rect.bottom - rect.top, pClipRect,bSmooth);
642 }
643 ////////////////////////////////////////////////////////////////////////////////
644 /**
645  * Draws the image in the specified device context, with support for alpha channel, alpha palette, transparency, opacity.
646  * \param hdc : destination device context
647  * \param x,y : (optional) offset
648  * \param cx,cy : (optional) size.
649  *                 - If cx or cy are not specified (or less than 0), the normal width or height will be used
650  *                 - If cx or cy are different than width or height, the image will be stretched
651  *
652  * \param pClipRect : limit the drawing operations inside a given rectangle in the output device context.
653  * \param bSmooth : activates a bilinear filter that will enhance the appearence for zommed pictures.
654  *                   Quite slow. Needs CXIMAGE_SUPPORT_INTERPOLATION.
655  * \return true if everything is ok
656  */
657 long CxImage::Draw(HDC hdc, long x, long y, long cx, long cy, RECT* pClipRect, bool bSmooth)
658 {
659         if((pDib==0)||(hdc==0)||(cx==0)||(cy==0)||(!info.bEnabled)) return 0;
660
661         if (cx < 0) cx = head.biWidth;
662         if (cy < 0) cy = head.biHeight;
663         bool bTransparent = info.nBkgndIndex >= 0;
664         bool bAlpha = pAlpha != 0;
665
666         //required for MM_ANISOTROPIC, MM_HIENGLISH, and similar modes [Greg Peatfield]
667         int hdc_Restore = ::SaveDC(hdc);
668         if (!hdc_Restore) 
669                 return 0;
670
671 #if !defined (_WIN32_WCE)
672         RECT mainbox; // (experimental) 
673         if (pClipRect){
674                 GetClipBox(hdc,&mainbox);
675                 HRGN rgn = CreateRectRgnIndirect(pClipRect);
676                 ExtSelectClipRgn(hdc,rgn,RGN_AND);
677                 DeleteObject(rgn);
678         }
679 #endif
680
681         //find the smallest area to paint
682         RECT clipbox,paintbox;
683         GetClipBox(hdc,&clipbox);
684
685         paintbox.top = min(clipbox.bottom,max(clipbox.top,y));
686         paintbox.left = min(clipbox.right,max(clipbox.left,x));
687         paintbox.right = max(clipbox.left,min(clipbox.right,x+cx));
688         paintbox.bottom = max(clipbox.top,min(clipbox.bottom,y+cy));
689
690         long destw = paintbox.right - paintbox.left;
691         long desth = paintbox.bottom - paintbox.top;
692
693         if (!(bTransparent || bAlpha || info.bAlphaPaletteEnabled)){
694                 if (cx==head.biWidth && cy==head.biHeight){ //NORMAL
695 #if !defined (_WIN32_WCE)
696                         SetStretchBltMode(hdc,COLORONCOLOR);
697 #endif
698                         SetDIBitsToDevice(hdc, x, y, cx, cy, 0, 0, 0, cy,
699                                                 info.pImage,(BITMAPINFO*)pDib,DIB_RGB_COLORS);
700                 } else { //STRETCH
701                         //pixel informations
702                         RGBQUAD c={0,0,0,0};
703                         //Preparing Bitmap Info
704                         BITMAPINFO bmInfo;
705                         memset(&bmInfo.bmiHeader,0,sizeof(BITMAPINFOHEADER));
706                         bmInfo.bmiHeader.biSize=sizeof(BITMAPINFOHEADER);
707                         bmInfo.bmiHeader.biWidth=destw;
708                         bmInfo.bmiHeader.biHeight=desth;
709                         bmInfo.bmiHeader.biPlanes=1;
710                         bmInfo.bmiHeader.biBitCount=24;
711                         BYTE *pbase;    //points to the final dib
712                         BYTE *pdst;             //current pixel from pbase
713                         BYTE *ppix;             //current pixel from image
714                         //get the background
715                         HDC TmpDC=CreateCompatibleDC(hdc);
716                         HBITMAP TmpBmp=CreateDIBSection(hdc,&bmInfo,DIB_RGB_COLORS,(void**)&pbase,0,0);
717                         HGDIOBJ TmpObj=SelectObject(TmpDC,TmpBmp);
718
719                         if (pbase){
720                                 long xx,yy;
721                                 long sx,sy;
722                                 float dx,dy;
723                                 BYTE *psrc;
724
725                                 long ew = ((((24 * destw) + 31) / 32) * 4);
726                                 long ymax = paintbox.bottom;
727                                 long xmin = paintbox.left;
728                                 float fx=(float)head.biWidth/(float)cx;
729                                 float fy=(float)head.biHeight/(float)cy;
730
731                                 for(yy=0;yy<desth;yy++){
732                                         dy = head.biHeight-(ymax-yy-y)*fy;
733                                         sy = max(0L,(long)floor(dy));
734                                         psrc = info.pImage+sy*info.dwEffWidth;
735                                         pdst = pbase+yy*ew;
736                                         for(xx=0;xx<destw;xx++){
737                                                 dx = (xx+xmin-x)*fx;
738                                                 sx = max(0L,(long)floor(dx));
739 #if CXIMAGE_SUPPORT_INTERPOLATION
740                                                 if (bSmooth){
741                                                         if (fx > 1 && fy > 1) { 
742                                                                 c = GetAreaColorInterpolated(dx - 0.5f, dy - 0.5f, fx, fy, CxImage::IM_BILINEAR, CxImage::OM_REPEAT); 
743                                                         } else { 
744                                                                 c = GetPixelColorInterpolated(dx - 0.5f, dy - 0.5f, CxImage::IM_BILINEAR, CxImage::OM_REPEAT); 
745                                                         } 
746                                                 } else
747 #endif //CXIMAGE_SUPPORT_INTERPOLATION
748                                                 {
749                                                         if (head.biClrUsed){
750                                                                 c=GetPaletteColor(GetPixelIndex(sx,sy));
751                                                         } else {
752                                                                 ppix = psrc + sx*3;
753                                                                 c.rgbBlue = *ppix++;
754                                                                 c.rgbGreen= *ppix++;
755                                                                 c.rgbRed  = *ppix;
756                                                         }
757                                                 }
758                                                 *pdst++=c.rgbBlue;
759                                                 *pdst++=c.rgbGreen;
760                                                 *pdst++=c.rgbRed;
761                                         }
762                                 }
763                         }
764                         //paint the image & cleanup
765                         SetDIBitsToDevice(hdc,paintbox.left,paintbox.top,destw,desth,0,0,0,desth,pbase,&bmInfo,0);
766                         DeleteObject(SelectObject(TmpDC,TmpObj));
767                         DeleteDC(TmpDC);
768                 }
769         } else {        // draw image with transparent/alpha blending
770         //////////////////////////////////////////////////////////////////
771                 //Alpha blend - Thanks to Florian Egel
772
773                 //pixel informations
774                 RGBQUAD c={0,0,0,0};
775                 RGBQUAD ct = GetTransColor();
776                 long* pc = (long*)&c;
777                 long* pct= (long*)&ct;
778                 long cit = GetTransIndex();
779                 long ci = 0;
780
781                 //Preparing Bitmap Info
782                 BITMAPINFO bmInfo;
783                 memset(&bmInfo.bmiHeader,0,sizeof(BITMAPINFOHEADER));
784                 bmInfo.bmiHeader.biSize=sizeof(BITMAPINFOHEADER);
785                 bmInfo.bmiHeader.biWidth=destw;
786                 bmInfo.bmiHeader.biHeight=desth;
787                 bmInfo.bmiHeader.biPlanes=1;
788                 bmInfo.bmiHeader.biBitCount=24;
789
790                 BYTE *pbase;    //points to the final dib
791                 BYTE *pdst;             //current pixel from pbase
792                 BYTE *ppix;             //current pixel from image
793
794                 //get the background
795                 HDC TmpDC=CreateCompatibleDC(hdc);
796                 HBITMAP TmpBmp=CreateDIBSection(hdc,&bmInfo,DIB_RGB_COLORS,(void**)&pbase,0,0);
797                 HGDIOBJ TmpObj=SelectObject(TmpDC,TmpBmp);
798                 BitBlt(TmpDC,0,0,destw,desth,hdc,paintbox.left,paintbox.top,SRCCOPY);
799
800                 if (pbase){
801                         long xx,yy,alphaoffset,ix,iy;
802                         BYTE a,a1,*psrc;
803                         long ew = ((((24 * destw) + 31) / 32) * 4);
804                         long ymax = paintbox.bottom;
805                         long xmin = paintbox.left;
806
807                         if (cx!=head.biWidth || cy!=head.biHeight){
808                                 //STRETCH
809                                 float fx=(float)head.biWidth/(float)cx;
810                                 float fy=(float)head.biHeight/(float)cy;
811                                 float dx,dy;
812                                 long sx,sy;
813                                 
814                                 for(yy=0;yy<desth;yy++){
815                                         dy = head.biHeight-(ymax-yy-y)*fy;
816                                         sy = max(0L,(long)floor(dy));
817
818                                         alphaoffset = sy*head.biWidth;
819                                         pdst = pbase + yy*ew;
820                                         psrc = info.pImage + sy*info.dwEffWidth;
821
822                                         for(xx=0;xx<destw;xx++){
823                                                 dx = (xx+xmin-x)*fx;
824                                                 sx = max(0L,(long)floor(dx));
825
826                                                 if (bAlpha) a=pAlpha[alphaoffset+sx]; else a=255;
827                                                 a =(BYTE)((a*(1+info.nAlphaMax))>>8);
828
829                                                 if (head.biClrUsed){
830                                                         ci = GetPixelIndex(sx,sy);
831 #if CXIMAGE_SUPPORT_INTERPOLATION
832                                                         if (bSmooth){
833                                                                 if (fx > 1 && fy > 1) { 
834                                                                         c = GetAreaColorInterpolated(dx - 0.5f, dy - 0.5f, fx, fy, CxImage::IM_BILINEAR, CxImage::OM_REPEAT); 
835                                                                 } else { 
836                                                                         c = GetPixelColorInterpolated(dx - 0.5f, dy - 0.5f, CxImage::IM_BILINEAR, CxImage::OM_REPEAT); 
837                                                                 } 
838                                                         } else
839 #endif //CXIMAGE_SUPPORT_INTERPOLATION
840                                                         {
841                                                                 c = GetPaletteColor(GetPixelIndex(sx,sy));
842                                                         }
843                                                         if (info.bAlphaPaletteEnabled){
844                                                                 a = (BYTE)((a*(1+c.rgbReserved))>>8);
845                                                         }
846                                                 } else {
847 #if CXIMAGE_SUPPORT_INTERPOLATION
848                                                         if (bSmooth){
849                                                                 if (fx > 1 && fy > 1) { 
850                                                                         c = GetAreaColorInterpolated(dx - 0.5f, dy - 0.5f, fx, fy, CxImage::IM_BILINEAR, CxImage::OM_REPEAT); 
851                                                                 } else { 
852                                                                         c = GetPixelColorInterpolated(dx - 0.5f, dy - 0.5f, CxImage::IM_BILINEAR, CxImage::OM_REPEAT); 
853                                                                 } 
854                                                         } else
855 #endif //CXIMAGE_SUPPORT_INTERPOLATION
856                                                         {
857                                                                 ppix = psrc + sx*3;
858                                                                 c.rgbBlue = *ppix++;
859                                                                 c.rgbGreen= *ppix++;
860                                                                 c.rgbRed  = *ppix;
861                                                         }
862                                                 }
863                                                 //if (*pc!=*pct || !bTransparent){
864                                                 //if ((head.biClrUsed && ci!=cit) || ((!head.biClrUsed||bSmooth) && *pc!=*pct) || !bTransparent){
865                                                 if ((head.biClrUsed && ci!=cit) || (!head.biClrUsed && *pc!=*pct) || !bTransparent){
866                                                         // DJT, assume many pixels are fully transparent or opaque and thus avoid multiplication
867                                                         if (a == 0) {                   // Transparent, retain dest 
868                                                                 pdst+=3; 
869                                                         } else if (a == 255) {  // opaque, ignore dest 
870                                                                 *pdst++= c.rgbBlue; 
871                                                                 *pdst++= c.rgbGreen; 
872                                                                 *pdst++= c.rgbRed; 
873                                                         } else {                                // semi transparent 
874                                                                 a1=(BYTE)~a;
875                                                                 *pdst++=(BYTE)((*pdst * a1 + a * c.rgbBlue)>>8); 
876                                                                 *pdst++=(BYTE)((*pdst * a1 + a * c.rgbGreen)>>8); 
877                                                                 *pdst++=(BYTE)((*pdst * a1 + a * c.rgbRed)>>8); 
878                                                         } 
879                                                 } else {
880                                                         pdst+=3;
881                                                 }
882                                         }
883                                 }
884                         } else {
885                                 //NORMAL
886                                 iy=head.biHeight-ymax+y;
887                                 for(yy=0;yy<desth;yy++,iy++){
888                                         alphaoffset=iy*head.biWidth;
889                                         ix=xmin-x;
890                                         pdst=pbase+yy*ew;
891                                         ppix=info.pImage+iy*info.dwEffWidth+ix*3;
892                                         for(xx=0;xx<destw;xx++,ix++){
893
894                                                 if (bAlpha) a=pAlpha[alphaoffset+ix]; else a=255;
895                                                 a = (BYTE)((a*(1+info.nAlphaMax))>>8);
896
897                                                 if (head.biClrUsed){
898                                                         ci = GetPixelIndex(ix,iy);
899                                                         c = GetPaletteColor((BYTE)ci);
900                                                         if (info.bAlphaPaletteEnabled){
901                                                                 a = (BYTE)((a*(1+c.rgbReserved))>>8);
902                                                         }
903                                                 } else {
904                                                         c.rgbBlue = *ppix++;
905                                                         c.rgbGreen= *ppix++;
906                                                         c.rgbRed  = *ppix++;
907                                                 }
908
909                                                 //if (*pc!=*pct || !bTransparent){
910                                                 if ((head.biClrUsed && ci!=cit) || (!head.biClrUsed && *pc!=*pct) || !bTransparent){
911                                                         // DJT, assume many pixels are fully transparent or opaque and thus avoid multiplication
912                                                         if (a == 0) {                   // Transparent, retain dest 
913                                                                 pdst+=3; 
914                                                         } else if (a == 255) {  // opaque, ignore dest 
915                                                                 *pdst++= c.rgbBlue; 
916                                                                 *pdst++= c.rgbGreen; 
917                                                                 *pdst++= c.rgbRed; 
918                                                         } else {                                // semi transparent 
919                                                                 a1=(BYTE)~a;
920                                                                 *pdst++=(BYTE)((*pdst * a1 + a * c.rgbBlue)>>8); 
921                                                                 *pdst++=(BYTE)((*pdst * a1 + a * c.rgbGreen)>>8); 
922                                                                 *pdst++=(BYTE)((*pdst * a1 + a * c.rgbRed)>>8); 
923                                                         } 
924                                                 } else {
925                                                         pdst+=3;
926                                                 }
927                                         }
928                                 }
929                         }
930                 }
931                 //paint the image & cleanup
932                 SetDIBitsToDevice(hdc,paintbox.left,paintbox.top,destw,desth,0,0,0,desth,pbase,&bmInfo,0);
933                 DeleteObject(SelectObject(TmpDC,TmpObj));
934                 DeleteDC(TmpDC);
935         }
936
937 #if !defined (_WIN32_WCE)
938         if (pClipRect){  // (experimental)
939                 HRGN rgn = CreateRectRgnIndirect(&mainbox);
940                 ExtSelectClipRgn(hdc,rgn,RGN_OR);
941                 DeleteObject(rgn);
942         }
943 #endif
944
945         ::RestoreDC(hdc,hdc_Restore);
946         return 1;
947 }
948 ////////////////////////////////////////////////////////////////////////////////
949 long CxImage::Draw2(HDC hdc, const RECT& rect)
950 {
951         return Draw2(hdc, rect.left, rect.top, rect.right - rect.left, rect.bottom - rect.top);
952 }
953 ////////////////////////////////////////////////////////////////////////////////
954 /**
955  * Draws (stretch) the image with single transparency support
956  * \param hdc : destination device context
957  * \param x,y : (optional) offset
958  * \param cx,cy : (optional) size.
959  *                 - If cx or cy are not specified (or less than 0), the normal width or height will be used
960  *                 - If cx or cy are different than width or height, the image will be stretched
961  *
962  * \return true if everything is ok
963  */
964 long CxImage::Draw2(HDC hdc, long x, long y, long cx, long cy)
965 {
966         if((pDib==0)||(hdc==0)||(cx==0)||(cy==0)||(!info.bEnabled)) return 0;
967         if (cx < 0) cx = head.biWidth;
968         if (cy < 0) cy = head.biHeight;
969         bool bTransparent = (info.nBkgndIndex >= 0);
970
971         //required for MM_ANISOTROPIC, MM_HIENGLISH, and similar modes [Greg Peatfield]
972         int hdc_Restore = ::SaveDC(hdc);
973         if (!hdc_Restore) 
974                 return 0;
975
976         if (!bTransparent){
977 #if !defined (_WIN32_WCE)
978                 SetStretchBltMode(hdc,COLORONCOLOR);    
979 #endif
980                 StretchDIBits(hdc, x, y, cx, cy, 0, 0, head.biWidth, head.biHeight,
981                                                 info.pImage,(BITMAPINFO*)pDib, DIB_RGB_COLORS,SRCCOPY);
982         } else {
983                 // draw image with transparent background
984                 const int safe = 0; // or else GDI fails in the following - sometimes 
985                 RECT rcDst = {x+safe, y+safe, x+cx, y+cy};
986                 if (RectVisible(hdc, &rcDst)){
987                 /////////////////////////////////////////////////////////////////
988                         // True Mask Method - Thanks to Paul Reynolds and Ron Gery
989                         int nWidth = head.biWidth;
990                         int nHeight = head.biHeight;
991                         // Create two memory dcs for the image and the mask
992                         HDC dcImage=CreateCompatibleDC(hdc);
993                         HDC dcTrans=CreateCompatibleDC(hdc);
994                         // Select the image into the appropriate dc
995                         HBITMAP bm = CreateCompatibleBitmap(hdc, nWidth, nHeight);
996                         HBITMAP pOldBitmapImage = (HBITMAP)SelectObject(dcImage,bm);
997 #if !defined (_WIN32_WCE)
998                         SetStretchBltMode(dcImage,COLORONCOLOR);
999 #endif
1000                         StretchDIBits(dcImage, 0, 0, nWidth, nHeight, 0, 0, nWidth, nHeight,
1001                                                         info.pImage,(BITMAPINFO*)pDib,DIB_RGB_COLORS,SRCCOPY);
1002
1003                         // Create the mask bitmap
1004                         HBITMAP bitmapTrans = CreateBitmap(nWidth, nHeight, 1, 1, NULL);
1005                         // Select the mask bitmap into the appropriate dc
1006                         HBITMAP pOldBitmapTrans = (HBITMAP)SelectObject(dcTrans, bitmapTrans);
1007                         // Build mask based on transparent colour
1008                         RGBQUAD rgbBG;
1009                         if (head.biBitCount<24) rgbBG = GetPaletteColor((BYTE)info.nBkgndIndex);
1010                         else rgbBG = info.nBkgndColor;
1011                         COLORREF crColour = RGB(rgbBG.rgbRed, rgbBG.rgbGreen, rgbBG.rgbBlue);
1012                         COLORREF crOldBack = SetBkColor(dcImage,crColour);
1013                         BitBlt(dcTrans,0, 0, nWidth, nHeight, dcImage, 0, 0, SRCCOPY);
1014
1015                         // Do the work - True Mask method - cool if not actual display
1016                         StretchBlt(hdc,x, y,cx,cy, dcImage, 0, 0, nWidth, nHeight, SRCINVERT);
1017                         StretchBlt(hdc,x, y,cx,cy, dcTrans, 0, 0, nWidth, nHeight, SRCAND);
1018                         StretchBlt(hdc,x, y,cx,cy, dcImage, 0, 0, nWidth, nHeight, SRCINVERT);
1019
1020                         // Restore settings
1021                         SelectObject(dcImage,pOldBitmapImage);
1022                         SelectObject(dcTrans,pOldBitmapTrans);
1023                         SetBkColor(hdc,crOldBack);
1024                         DeleteObject( bitmapTrans );  // RG 29/01/2002
1025                         DeleteDC(dcImage);
1026                         DeleteDC(dcTrans);
1027                         DeleteObject(bm);
1028                 }
1029         }
1030         ::RestoreDC(hdc,hdc_Restore);
1031         return 1;
1032 }
1033 ////////////////////////////////////////////////////////////////////////////////
1034 long CxImage::Stretch(HDC hdc, const RECT& rect, DWORD dwRop)
1035 {
1036         return Stretch(hdc, rect.left, rect.top, rect.right - rect.left, rect.bottom - rect.top, dwRop);
1037 }
1038 ////////////////////////////////////////////////////////////////////////////////
1039 /**
1040  * Stretch the image. Obsolete: use Draw() or Draw2()
1041  * \param hdc : destination device context
1042  * \param xoffset,yoffset : (optional) offset
1043  * \param xsize,ysize : size.
1044  * \param dwRop : raster operation code (see BitBlt documentation)
1045  * \return true if everything is ok
1046  */
1047 long CxImage::Stretch(HDC hdc, long xoffset, long yoffset, long xsize, long ysize, DWORD dwRop)
1048 {
1049         if((pDib)&&(hdc)) {
1050                 //palette must be correctly filled
1051 #if !defined (_WIN32_WCE)
1052                 SetStretchBltMode(hdc,COLORONCOLOR);    
1053 #endif
1054                 StretchDIBits(hdc, xoffset, yoffset,
1055                                         xsize, ysize, 0, 0, head.biWidth, head.biHeight,
1056                                         info.pImage,(BITMAPINFO*)pDib,DIB_RGB_COLORS,dwRop);
1057                 return 1;
1058         }
1059         return 0;
1060 }
1061 ////////////////////////////////////////////////////////////////////////////////
1062 /**
1063  * Tiles the device context in the specified rectangle with the image.
1064  * \param hdc : destination device context
1065  * \param rc : tiled rectangle in the output device context
1066  * \return true if everything is ok
1067  */
1068 long CxImage::Tile(HDC hdc, RECT *rc)
1069 {
1070         if((pDib)&&(hdc)&&(rc)) {
1071                 int w = rc->right - rc->left;
1072                 int h = rc->bottom - rc->top;
1073                 int x,y,z;
1074                 int bx=head.biWidth;
1075                 int by=head.biHeight;
1076                 for (y = 0 ; y < h ; y += by){
1077                         if ((y+by)>h) by=h-y;
1078                         z=bx;
1079                         for (x = 0 ; x < w ; x += z){
1080                                 if ((x+z)>w) z=w-x;
1081                                 RECT r = {rc->left + x,rc->top + y,rc->left + x + z,rc->top + y + by};
1082                                 Draw(hdc,rc->left + x, rc->top + y,-1,-1,&r);
1083                         }
1084                 }
1085                 return 1;
1086         }
1087         return 0;
1088 }
1089 ////////////////////////////////////////////////////////////////////////////////
1090 // For UNICODE support: char -> TCHAR
1091 long CxImage::DrawString(HDC hdc, long x, long y, const TCHAR* text, RGBQUAD color, const TCHAR* font, long lSize, long lWeight, BYTE bItalic, BYTE bUnderline, bool bSetAlpha)
1092 //long CxImage::DrawString(HDC hdc, long x, long y, const char* text, RGBQUAD color, const char* font, long lSize, long lWeight, BYTE bItalic, BYTE bUnderline, bool bSetAlpha)
1093 {
1094         if (IsValid()){
1095                 //get the background
1096                 HDC pDC;
1097                 if (hdc) pDC=hdc; else pDC = ::GetDC(0);
1098                 if (pDC==NULL) return 0;
1099                 HDC TmpDC=CreateCompatibleDC(pDC);
1100                 if (hdc==NULL) ::ReleaseDC(0, pDC);
1101                 if (TmpDC==NULL) return 0;
1102                 //choose the font
1103                 HFONT m_Font;
1104                 LOGFONT* m_pLF;
1105                 m_pLF=(LOGFONT*)calloc(1,sizeof(LOGFONT));
1106                 _tcsncpy(m_pLF->lfFaceName,font,31);    // For UNICODE support
1107                 //strncpy(m_pLF->lfFaceName,font,31);
1108                 m_pLF->lfHeight=lSize;
1109                 m_pLF->lfWeight=lWeight;
1110                 m_pLF->lfItalic=bItalic;
1111                 m_pLF->lfUnderline=bUnderline;
1112                 m_Font=CreateFontIndirect(m_pLF);
1113                 //select the font in the dc
1114                 HFONT pOldFont=NULL;
1115                 if (m_Font)
1116                         pOldFont = (HFONT)SelectObject(TmpDC,m_Font);
1117                 else
1118                         pOldFont = (HFONT)SelectObject(TmpDC,GetStockObject(DEFAULT_GUI_FONT));
1119
1120                 //Set text color
1121                 SetTextColor(TmpDC,RGB(255,255,255));
1122                 SetBkColor(TmpDC,RGB(0,0,0));
1123                 //draw the text
1124                 SetBkMode(TmpDC,OPAQUE);
1125                 //Set text position;
1126                 RECT pos = {0,0,0,0};
1127                 //long len = (long)strlen(text);
1128                 long len = (long)_tcslen(text); // For UNICODE support
1129                 ::DrawText(TmpDC,text,len,&pos,DT_CALCRECT);
1130                 pos.right+=pos.bottom; //for italics
1131
1132                 //Preparing Bitmap Info
1133                 long width=pos.right;
1134                 long height=pos.bottom;
1135                 BITMAPINFO bmInfo;
1136                 memset(&bmInfo.bmiHeader,0,sizeof(BITMAPINFOHEADER));
1137                 bmInfo.bmiHeader.biSize=sizeof(BITMAPINFOHEADER);
1138                 bmInfo.bmiHeader.biWidth=width;
1139                 bmInfo.bmiHeader.biHeight=height;
1140                 bmInfo.bmiHeader.biPlanes=1;
1141                 bmInfo.bmiHeader.biBitCount=24;
1142                 BYTE *pbase; //points to the final dib
1143
1144                 HBITMAP TmpBmp=CreateDIBSection(TmpDC,&bmInfo,DIB_RGB_COLORS,(void**)&pbase,0,0);
1145                 HGDIOBJ TmpObj=SelectObject(TmpDC,TmpBmp);
1146                 memset(pbase,0,height*((((24 * width) + 31) / 32) * 4));
1147
1148                 ::DrawText(TmpDC,text,len,&pos,0);
1149
1150                 CxImage itext;
1151                 itext.CreateFromHBITMAP(TmpBmp);
1152
1153                 y=head.biHeight-y-1;
1154                 for (long ix=0;ix<width;ix++){
1155                         for (long iy=0;iy<height;iy++){
1156                                 if (itext.GetPixelColor(ix,iy).rgbBlue) SetPixelColor(x+ix,y+iy,color,bSetAlpha);
1157                         }
1158                 }
1159
1160                 //cleanup
1161                 if (pOldFont) SelectObject(TmpDC,pOldFont);
1162                 DeleteObject(m_Font);
1163                 free(m_pLF);
1164                 DeleteObject(SelectObject(TmpDC,TmpObj));
1165                 DeleteDC(TmpDC);
1166         }
1167
1168         return 1;
1169 }
1170 ////////////////////////////////////////////////////////////////////////////////
1171 // <VATI>
1172 long CxImage::DrawStringEx(HDC hdc, long x, long y, CXTEXTINFO *pTextType, bool bSetAlpha )
1173 {
1174         if (!IsValid())
1175         return -1;
1176     
1177         //get the background
1178         HDC pDC;
1179         if (hdc) pDC=hdc; else pDC = ::GetDC(0);
1180         if (pDC==NULL) return 0;
1181         HDC TmpDC=CreateCompatibleDC(pDC);
1182         if (hdc==NULL) ::ReleaseDC(0, pDC);
1183         if (TmpDC==NULL) return 0;
1184
1185     //choose the font
1186         HFONT m_Font;
1187     m_Font=CreateFontIndirect( &pTextType->lfont );
1188     
1189     // get colors in RGBQUAD
1190     RGBQUAD p_forecolor = RGBtoRGBQUAD(pTextType->fcolor);
1191     RGBQUAD p_backcolor = RGBtoRGBQUAD(pTextType->bcolor);
1192
1193     // check alignment and re-set default if necessary
1194     if ( pTextType->align != DT_CENTER &&
1195          pTextType->align != DT_LEFT &&
1196          pTextType->align != DT_RIGHT )
1197         pTextType->align = DT_CENTER;
1198
1199     // check rounding radius and re-set default if necessary
1200     if ( pTextType->b_round > 50 )
1201         pTextType->b_round = 10;
1202
1203     // check opacity and re-set default if necessary
1204     if ( pTextType->b_opacity > 1. || pTextType->b_opacity < .0 )
1205         pTextType->b_opacity = 0.;
1206
1207     //select the font in the dc
1208         HFONT pOldFont=NULL;
1209         if (m_Font)
1210                 pOldFont = (HFONT)SelectObject(TmpDC,m_Font);
1211         else
1212                 pOldFont = (HFONT)SelectObject(TmpDC,GetStockObject(DEFAULT_GUI_FONT));
1213
1214         //Set text color
1215     SetTextColor(TmpDC,RGB(255,255,255));
1216         SetBkColor(TmpDC,RGB(0,0,0));
1217         SetBkMode(TmpDC,OPAQUE);
1218         //Set text position;
1219         RECT pos = {0,0,0,0};
1220         
1221     // get text length and number of lines
1222     long i=0, numlines=1, len=(long)_tcsclen(pTextType->text);
1223     while (i<len)
1224     {
1225         if ( pTextType->text[i++]==13 )
1226             numlines++;
1227     }
1228
1229         ::DrawText(TmpDC, pTextType->text, len, &pos, /*DT_EDITCONTROL|DT_EXTERNALLEADING|*/DT_NOPREFIX | DT_CALCRECT );
1230
1231     // increase only if it's really italics, and only one line height
1232         if ( pTextType->lfont.lfItalic ) 
1233         pos.right += pos.bottom/2/numlines; 
1234
1235     // background frame and rounding radius
1236         int frame = 0, roundR = 0;
1237     if ( pTextType->opaque )
1238     {
1239         roundR= (int)(pos.bottom/numlines * pTextType->b_round / 100 ) ;
1240         frame = (int)(/*3.5 + */0.29289*roundR ) ;
1241         pos.right += pos.bottom/numlines/3 ; // JUST FOR BEAUTY
1242     }
1243
1244         //Preparing Bitmap Info
1245         long width=pos.right +frame*2;
1246         long height=pos.bottom +frame*2;
1247         BITMAPINFO bmInfo;
1248         memset(&bmInfo.bmiHeader,0,sizeof(BITMAPINFOHEADER));
1249         bmInfo.bmiHeader.biSize=sizeof(BITMAPINFOHEADER);
1250         bmInfo.bmiHeader.biWidth=width;
1251         bmInfo.bmiHeader.biHeight=height;
1252         bmInfo.bmiHeader.biPlanes=1;
1253         bmInfo.bmiHeader.biBitCount=24;
1254         BYTE *pbase; //points to the final dib
1255
1256         HBITMAP TmpBmp=CreateDIBSection(TmpDC,&bmInfo,DIB_RGB_COLORS,(void**)&pbase,0,0);
1257         HGDIOBJ TmpObj=SelectObject(TmpDC,TmpBmp);
1258         memset(pbase,0,height*((((24 * width) + 31) / 32) * 4));
1259
1260         ::DrawText(TmpDC,pTextType->text,len, &pos, /*DT_EDITCONTROL|DT_EXTERNALLEADING|*/DT_NOPREFIX| pTextType->align );
1261     
1262         CxImage itext;
1263         itext.CreateFromHBITMAP(TmpBmp);
1264     y=head.biHeight-y-1;
1265
1266         itext.Negative();
1267
1268         if (pTextType->smooth==FALSE){
1269                 itext.Threshold(128);
1270         } else {
1271                 //itext.TextBlur();
1272         }
1273
1274     //move the insertion point according to alignment type
1275     // DT_CENTER: cursor points to the center of text rectangle
1276     // DT_RIGHT:  cursor points to right side end of text rectangle
1277     // DT_LEFT:   cursor points to left end of text rectangle
1278     if ( pTextType->align == DT_CENTER )
1279         x -= width/2;
1280     else if ( pTextType->align == DT_RIGHT )
1281         x -= width;
1282     if (x<0) x=0;
1283     
1284     //draw the background first, if it exists
1285     long ix,iy;
1286     if ( pTextType->opaque )
1287     {
1288         int ixf=0; 
1289         for (ix=0;ix<width;ix++)
1290         {
1291             if ( ix<=roundR )
1292                 ixf = (int)(.5+roundR-sqrt((float)(roundR*roundR-(ix-roundR)*(ix-roundR))));
1293             else if ( ix>=width-roundR-1 )
1294                 ixf = (int)(.5+roundR-sqrt((float)(roundR*roundR-(width-1-ix-roundR)*(width-1-ix-roundR))));
1295             else
1296                 ixf=0;
1297
1298             for (iy=0;iy<height;iy++)
1299             {
1300                 if ( (ix<=roundR && ( iy > height-ixf-1 || iy < ixf )) ||
1301                      (ix>=width-roundR-1 && ( iy > height-ixf-1 || iy < ixf )) )
1302                     continue;
1303                 else
1304                     if ( pTextType->b_opacity > 0.0 && pTextType->b_opacity < 1.0 )
1305                     {
1306                         RGBQUAD bcolor, pcolor;
1307                         // calculate a transition color from original image to background color:
1308                         pcolor = GetPixelColor(x+ix,y+iy);
1309                                                 bcolor.rgbBlue = (unsigned char)(pTextType->b_opacity * pcolor.rgbBlue + (1.0-pTextType->b_opacity) * p_backcolor.rgbBlue );
1310                         bcolor.rgbRed = (unsigned char)(pTextType->b_opacity * pcolor.rgbRed + (1.0-pTextType->b_opacity) * p_backcolor.rgbRed ) ;
1311                         bcolor.rgbGreen = (unsigned char)(pTextType->b_opacity * pcolor.rgbGreen + (1.0-pTextType->b_opacity) * p_backcolor.rgbGreen ) ;
1312                         bcolor.rgbReserved = 0;
1313                         SetPixelColor(x+ix,y+iy,bcolor,bSetAlpha);
1314                     }
1315                     else
1316                         SetPixelColor(x+ix,y+iy,p_backcolor,bSetAlpha);
1317                         }
1318                 }
1319     }
1320
1321     // draw the text itself
1322     for (ix=0;ix<width;ix++)
1323     {
1324                 for (iy=0;iy<height;iy++)
1325         {
1326                         RGBQUAD pcolor = GetPixelColor(x+ix,y+iy);
1327                         RGBQUAD tcolor = itext.GetPixelColor(ix,iy);
1328             if (tcolor.rgbBlue!=255){
1329                                 float a = tcolor.rgbBlue/255.0f;
1330                                 pcolor.rgbBlue  = (unsigned char)(a * (pcolor.rgbBlue  - p_forecolor.rgbBlue)  + p_forecolor.rgbBlue );
1331                 pcolor.rgbRed   = (unsigned char)(a * (pcolor.rgbRed   - p_forecolor.rgbRed)   + p_forecolor.rgbRed ) ;
1332                 pcolor.rgbGreen = (unsigned char)(a * (pcolor.rgbGreen - p_forecolor.rgbGreen) + p_forecolor.rgbGreen );
1333                 pcolor.rgbReserved = 0;
1334                 SetPixelColor(x+ix+frame,y+iy-frame,pcolor,bSetAlpha);
1335               //SetPixelColor(x+ix+frame,y+iy-frame,p_forecolor,bSetAlpha);
1336                         }
1337                 }
1338         }
1339
1340         //cleanup
1341     if (pOldFont) SelectObject(TmpDC,pOldFont);
1342         DeleteObject(m_Font);
1343         DeleteObject(SelectObject(TmpDC,TmpObj));
1344         DeleteDC(TmpDC);
1345         return 1;
1346 }
1347
1348 //////////////////////////////////////////////////////////////////////////////
1349 void CxImage::InitTextInfo( CXTEXTINFO *txt )
1350 {
1351
1352     memset( txt, 0, sizeof(CXTEXTINFO));
1353     
1354     // LOGFONT defaults
1355     txt->lfont.lfHeight        = -36; 
1356     txt->lfont.lfCharSet       = EASTEUROPE_CHARSET; // just for Central-European users 
1357     txt->lfont.lfWeight        = FW_NORMAL;
1358     txt->lfont.lfWidth         = 0; 
1359     txt->lfont.lfEscapement    = 0; 
1360     txt->lfont.lfOrientation   = 0; 
1361     txt->lfont.lfItalic        = FALSE; 
1362     txt->lfont.lfUnderline     = FALSE; 
1363     txt->lfont.lfStrikeOut     = FALSE; 
1364     txt->lfont.lfOutPrecision  = OUT_DEFAULT_PRECIS; 
1365     txt->lfont.lfClipPrecision = CLIP_DEFAULT_PRECIS; 
1366     txt->lfont.lfQuality       = PROOF_QUALITY; 
1367     txt->lfont.lfPitchAndFamily= DEFAULT_PITCH | FF_DONTCARE ; 
1368     _stprintf( txt->lfont.lfFaceName, _T("Arial")); //use TCHAR mappings <Cesar M>
1369
1370     // initial colors
1371     txt->fcolor = RGB( 255,255,160 );  // default foreground: light goldyellow
1372     txt->bcolor = RGB(   0, 80,160 );  // default background: light blue
1373
1374     // background
1375     txt->opaque    = TRUE;  // text has a non-transparent background;
1376         txt->smooth    = TRUE;
1377     txt->b_opacity = 0.0;   // default: opaque background
1378     txt->b_outline = 0;     // default: no outline (OUTLINE NOT IMPLEMENTED AT THIS TIME)
1379     txt->b_round   = 20;    // default: rounding radius is 20% of the rectangle height
1380     // the text 
1381     _stprintf( txt->text, _T("Sample Text 01234õû")); // text use TCHAR mappings <Cesar M>
1382     txt->align = DT_CENTER;
1383     return;
1384 }
1385
1386 #if CXIMAGE_SUPPORT_LAYERS
1387 ////////////////////////////////////////////////////////////////////////////////
1388 long CxImage::LayerDrawAll(HDC hdc, const RECT& rect, RECT* pClipRect, bool bSmooth)
1389 {
1390         return LayerDrawAll(hdc, rect.left, rect.top, rect.right - rect.left, rect.bottom - rect.top, pClipRect,bSmooth);
1391 }
1392 ////////////////////////////////////////////////////////////////////////////////
1393 long CxImage::LayerDrawAll(HDC hdc, long x, long y, long cx, long cy, RECT* pClipRect, bool bSmooth)
1394 {
1395         long n=0;
1396         CxImage* pLayer;
1397         while(pLayer=GetLayer(n++)){
1398                 if (pLayer->Draw(hdc,x+pLayer->info.xOffset,y+pLayer->info.yOffset,cx,cy,pClipRect,bSmooth)==0)
1399                         return 0;
1400                 if (pLayer->LayerDrawAll(hdc,x+pLayer->info.xOffset,y+pLayer->info.yOffset,cx,cy,pClipRect,bSmooth)==0)
1401                         return 0;
1402         }
1403         return 1;
1404 }
1405 #endif //CXIMAGE_SUPPORT_LAYERS
1406
1407 ////////////////////////////////////////////////////////////////////////////////
1408 #endif //CXIMAGE_SUPPORT_WINDOWS
1409 ////////////////////////////////////////////////////////////////////////////////