source: liacs/MIR2010/SourceCode/cximage/ximawnd.cpp@ 320

Last change on this file since 320 was 95, checked in by Rick van der Zwet, 15 years ago

Bad boy, improper move of directory

File size: 45.2 KB
Line 
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
22struct 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
30int BytesPerLine(int nWidth, int nBitsPerPixel)
31{
32 return ( (nWidth * nBitsPerPixel + 31) & (~31) ) / 8;
33}
34
35int 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
63int 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////////////////////////////////////////////////////////////////////////////////
163long 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 */
181HANDLE 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 */
202bool 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 */
499HBITMAP 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 */
534bool 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)
576bool 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////////////////////////////////////////////////////////////////////////////////
639long 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 */
657long 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////////////////////////////////////////////////////////////////////////////////
949long 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 */
964long 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////////////////////////////////////////////////////////////////////////////////
1034long 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 */
1047long 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 */
1068long 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
1091long 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>
1172long 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//////////////////////////////////////////////////////////////////////////////
1349void 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////////////////////////////////////////////////////////////////////////////////
1388long 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////////////////////////////////////////////////////////////////////////////////
1393long 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////////////////////////////////////////////////////////////////////////////////
Note: See TracBrowser for help on using the repository browser.