From 7aff1e4cb053394db57c2814d5fe1e6493e0cc75 Mon Sep 17 00:00:00 2001 From: watcherhd Date: Sat, 26 Nov 2011 14:19:43 +0000 Subject: Project folders rename part 2 git-svn-id: http://miranda-plugins.googlecode.com/svn/trunk@214 e753b5eb-9565-29b2-b5c5-2cc6f99dfbcb --- FloatingContacts/bitmap_funcs.cpp | 1239 +++++++++++++++++++++++++++++++++++++ 1 file changed, 1239 insertions(+) create mode 100644 FloatingContacts/bitmap_funcs.cpp (limited to 'FloatingContacts/bitmap_funcs.cpp') diff --git a/FloatingContacts/bitmap_funcs.cpp b/FloatingContacts/bitmap_funcs.cpp new file mode 100644 index 0000000..3d92e7a --- /dev/null +++ b/FloatingContacts/bitmap_funcs.cpp @@ -0,0 +1,1239 @@ +/* +Popup Plus plugin for Miranda IM + +Copyright © 2002 Luca Santarelli, + © 2004-2007 Victor Pavlychko + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +*/ + +#include "stdhdr.h" +#include "bitmap_funcs.h" + +#include +#include + +#define PU_FONT_THRESHOLD 96 +#define PU_BMP_ACCURATE_ARITHMETICS + +#ifdef PU_BMP_ACCURATE_ARITHMETICS + #define PU_DIV255(x) ((x)/255) + #define PU_DIV128(x) ((x)/128) + typedef float pu_koef; +#else + #define PU_DIV255(x) ((x)>>8) + #define PU_DIV128(x) ((x)>>7) + typedef long pu_koef; +#endif + +MyBitmap::MyBitmap() +{ + dcBmp = 0; + hBmp = 0; + bits = 0; + width = height = 0; + bitsSave = 0; +} + +MyBitmap::MyBitmap(int w, int h) +{ + dcBmp = 0; + hBmp = 0; + bits = 0; + width = height = 0; + bitsSave = 0; + allocate(w,h); +} + +MyBitmap::MyBitmap(const char *fn, const char *fnAlpha) +{ + dcBmp = 0; + hBmp = 0; + bits = 0; + width = height = 0; + bitsSave = 0; + loadFromFile(fn, fnAlpha); +} + +MyBitmap::~MyBitmap() +{ + if (bitsSave) + delete [] bitsSave; + free(); +} + +void MyBitmap::setAlpha(BYTE level) +{ + if (!bits) return; + + GdiFlush(); + for (int i = 0; i < width*height; i++) + { + if (bits[i] & 0xff000000) + { + bits[i] = rgba(getr(bits[i])*level/255, getg(bits[i])*level/255, getb(bits[i])*level/255, geta(bits[i])*level/255); + } else + { + bits[i] = rgba(getr(bits[i])*level/255, getg(bits[i])*level/255, getb(bits[i])*level/255, level); + } + } +} + +void MyBitmap::setAlphaRect(int x1, int y1, int x2, int y2, BYTE level) +{ + if (!bits) return; + + GdiFlush(); + for (int i = y1; i < y2; i++) + for (int j = x1; j < x2; j++) + { + int idx = i * width + j; + if (bits[idx] & 0xff000000) + { + bits[idx] = rgba(getr(bits[idx])*level/255, getg(bits[idx])*level/255, getb(bits[idx])*level/255, geta(bits[idx])*level/255); + } else + { + bits[idx] = rgba(getr(bits[idx])*level/255, getg(bits[idx])*level/255, getb(bits[idx])*level/255, level); + } + } +} + +void MyBitmap::makeOpaque() +{ + if (!bits) return; + + GdiFlush(); + for (int i = 0; i < width*height; i++) + bits[i] |= 0xff000000; +} + +void MyBitmap::makeOpaqueRect(int x1, int y1, int x2, int y2) +{ + if (!bits) return; + + GdiFlush(); + for (int i = y1; i < y2; i++) + for (int j = x1; j < x2; j++) + { + int idx = i * width + j; + bits[idx] |= 0xff000000; + } +} + +void MyBitmap::saveAlpha(int x, int y, int w, int h) +{ + if (bitsSave) + delete [] bitsSave; + + GdiFlush(); + + if (!w) w = width; + if (!h) h = height; + + bitsSave = new COLOR32[w*h]; + COLOR32 *p1 = bitsSave; + + for (int i = 0; i < h; i++) + { + if (i+y < 0) continue; + if (i+y >= height) break; + COLOR32 *p2 = bits + (y+i)*width + x; + p1 = bitsSave + i*w; + for (int j = 0; j < w; j++) + { + if (j+x < 0) continue; + if (j+x >= width) break; + *p1++ = *p2++; + } + } +} + +void MyBitmap::restoreAlpha(int x, int y, int w, int h) +{ + if (!bitsSave) + return; + + GdiFlush(); + + if (!w) w = width; + if (!h) h = height; + + COLOR32 *p1 = bitsSave; + + for (int i = 0; i < h; i++) + { + if (i+y < 0) continue; + if (i+y >= height) break; + COLOR32 *p2 = bits + (y+i)*width + x; + p1 = bitsSave + i*w; + for (int j = 0; j < w; j++) + { + if (j+x < 0) continue; + if (j+x >= width) break; + if ((*p1&0x00ffffff) != (*p2&0x00ffffff)) + { + *p2 |= 0xff000000; + } else + { + *p2 = (*p2&0x00ffffff) | (*p1&0xff000000); + } + ++p1; + ++p2; + } + } + + delete [] bitsSave; + bitsSave = 0; +} + +void MyBitmap::DrawBits(COLOR32 *inbits, int inw, int inh, int x, int y, int w, int h) +{ + if (!(bits && inbits)) return; + + GdiFlush(); + + float kx = (float)inw / w; + float ky = (float)inh / h; + + if (x+w >= this->getWidth()) + w = this->getWidth() - x; + if (y+h >= this->getHeight()) + h = this->getHeight() - y; + + for (int i = 0; i < h; i++) + { + if (i+y < 0) continue; + if (i+y >= height) break; + for (int j = 0; j < w; j++) + { + if (j+x < 0) continue; + if (j+x >= width) break; + bits[(i+y)*width + (j+x)] = inbits[int(i*ky)*inw + int(j*kx)]; + } + } +} + +void MyBitmap::BlendBits(COLOR32 *inbits, int inw, int inh, int x, int y, int w, int h) +{ + if (!(bits && inbits)) return; + + GdiFlush(); + + float kx = (float)inw / w; + float ky = (float)inh / h; + + if (x+w >= this->getWidth()) + w = this->getWidth() - x; + if (y+h >= this->getHeight()) + h = this->getHeight() - y; + + for (int i = 0; i < h; i++) + { + if (i+y < 0) continue; + if (i+y >= height) break; + for (int j = 0; j < w; j++) + { + if (j+x < 0) continue; + if (j+x >= width) break; + COLOR32 src = inbits[int(i*ky)*inw + int(j*kx)]; + COLOR32 dst = bits[(i+y)*width + (j+x)]; + long alpha = geta(src); + bits[(i+y)*width + (j+x)] = rgba( + getr(src)+PU_DIV255((255-alpha)*getr(dst)), + getg(src)+PU_DIV255((255-alpha)*getg(dst)), + getb(src)+PU_DIV255((255-alpha)*getb(dst)), + geta(src)+PU_DIV255((255-alpha)*geta(dst)) + ); + } + } +} + +void MyBitmap::Blend(MyBitmap *bmp, int x, int y, int w, int h) +{ + if (!(bits && bmp && bmp->bits)) return; + + GdiFlush(); + + if (!w) w = bmp->width; + if (!h) h = bmp->height; + float kx = (float)bmp->width / w; + float ky = (float)bmp->height / h; + + if (x+w >= this->getWidth()) + w = this->getWidth() - x; + if (y+h >= this->getHeight()) + h = this->getHeight() - y; + + for (int i = 0; i < h; i++) + { + if (i+y < 0) continue; + if (i+y >= height) break; + for (int j = 0; j < w; j++) + { + if (j+x < 0) continue; + if (j+x >= width) break; + COLOR32 src = bmp->bits[int(i*ky)*bmp->width + int(j*kx)]; + COLOR32 dst = bits[(i+y)*width + (j+x)]; + long alpha = geta(src); + bits[(i+y)*width + (j+x)] = rgba( + getr(src)+PU_DIV255((255-alpha)*getr(dst)), + getg(src)+PU_DIV255((255-alpha)*getg(dst)), + getb(src)+PU_DIV255((255-alpha)*getb(dst)), + geta(src)+PU_DIV255((255-alpha)*geta(dst)) + ); + } + } +} + +void MyBitmap::Draw(MyBitmap *bmp, int x, int y, int w, int h) +{ + if (!(bits && bmp && bmp->bits)) return; + + GdiFlush(); + + if (!w) w = bmp->width; + if (!h) h = bmp->height; + + if (!x && !y && (w == width) && (h == height) && (w == bmp->width) && (h == bmp->height)) + { + // fast bitmap copy is possible good for animated avatars + CopyMemory(bits, bmp->bits, width*height*sizeof(COLOR32)); + return; + } + + float kx = (float)bmp->width / w; + float ky = (float)bmp->height / h; + + if (x+w >= this->getWidth()) + w = this->getWidth() - x; + if (y+h >= this->getHeight()) + h = this->getHeight() - y; + + for (int i = 0; i < h; i++) + { + if (i+y < 0) continue; + if (i+y >= height) break; + for (int j = 0; j < w; j++) + { + if (j+x < 0) continue; + if (j+x >= width) break; + bits[(i+y)*width + (j+x)] = bmp->bits[int(i*ky)*bmp->width + int(j*kx)]; + } + } +} + +void MyBitmap::BlendColorized(MyBitmap *bmp, int x, int y, int w, int h, COLOR32 color) +{ + if (!(bits && bmp && bmp->bits)) return; + + GdiFlush(); + + if (!w) w = bmp->width; + if (!h) h = bmp->height; + float kx = (float)bmp->width / w; + float ky = (float)bmp->height / h; + + // we should swap B and R channels when working with win32 COLORREF + float koef1r = (255 - getb(color)) / 128.0f; + float koef1g = (255 - getg(color)) / 128.0f; + float koef1b = (255 - getr(color)) / 128.0f; + + int br = - 255 + 2 * getb(color); + int bg = - 255 + 2 * getg(color); + int bb = - 255 + 2 * getr(color); + + float koef2r = (getb(color)) / 128.0f; + float koef2g = (getg(color)) / 128.0f; + float koef2b = (getr(color)) / 128.0f; + + for (int i = 0; i < h; i++) + { + if (i+y < 0) continue; + if (i+y >= height) break; + for (int j = 0; j < w; j++) + { + if (j+x < 0) continue; + if (j+x >= width) break; + +// COLOR32 cl = getr(bmp->bits[int(i*ky)*bmp->width + int(j*kx)]); +// bits[(i+y)*width + (j+x)] = (cl > 128) ? +// rgba(koef1r * cl + br, koef1g * cl + bg, koef1b * cl + bb, geta(bmp->bits[int(i*ky)*bmp->width + int(j*kx)])): +// rgba(koef2r * cl, koef2g * cl, koef2b * cl, geta(bmp->bits[int(i*ky)*bmp->width + int(j*kx)])); + + long alpha = geta(bmp->bits[int(i*ky)*bmp->width + int(j*kx)]); +// COLOR32 cl = getr(bmp->bits[int(i*ky)*bmp->width + int(j*kx)]); + COLOR32 cl = alpha ? getr(bmp->bits[int(i*ky)*bmp->width + int(j*kx)])*255/alpha : 0; +#pragma warning(push) +#pragma warning(disable: 4244) + COLOR32 src = (cl > 128) ? + rgba( + PU_DIV255((koef1r * cl + br)*alpha), + PU_DIV255((koef1g * cl + bg)*alpha), + PU_DIV255((koef1b * cl + bb)*alpha), + alpha): + rgba( + PU_DIV255(koef2r * cl * alpha), + PU_DIV255(koef2g * cl * alpha), + PU_DIV255(koef2b * cl * alpha), + alpha); +#pragma warning(pop) +// COLOR32 cl = getr(bmp->bits[int(i*ky)*bmp->width + int(j*kx)]); +// COLOR32 src = (cl > 128) ? +// rgba(koef1r * cl + br, koef1g * cl + bg, koef1b * cl + bb, alpha): +// rgba(koef2r * cl, koef2g * cl, koef2b * cl, alpha); + COLOR32 dst = bits[(i+y)*width + (j+x)]; +// long alpha = geta(src); + bits[(i+y)*width + (j+x)] = rgba( + getr(src)+PU_DIV255((255-alpha)*getr(dst)), + getg(src)+PU_DIV255((255-alpha)*getg(dst)), + getb(src)+PU_DIV255((255-alpha)*getb(dst)), + geta(src)+PU_DIV255((255-alpha)*geta(dst)) + ); + + } + } +} + +void MyBitmap::DrawColorized(MyBitmap *bmp, int x, int y, int w, int h, COLOR32 color) +{ + if (!(bits && bmp && bmp->bits)) return; + + GdiFlush(); + + if (!w) w = bmp->width; + if (!h) h = bmp->height; + float kx = (float)bmp->width / w; + float ky = (float)bmp->height / h; + + // we should swap B and R channels when working with win32 COLORREF + float koef1r = (255 - getb(color)) / 128.0f; + float koef1g = (255 - getg(color)) / 128.0f; + float koef1b = (255 - getr(color)) / 128.0f; + + int br = - 255 + 2 * getb(color); + int bg = - 255 + 2 * getg(color); + int bb = - 255 + 2 * getr(color); + + float koef2r = (getb(color)) / 128.0f; + float koef2g = (getg(color)) / 128.0f; + float koef2b = (getr(color)) / 128.0f; + + for (int i = 0; i < h; i++) + { + if (i+y < 0) continue; + if (i+y >= height) break; + for (int j = 0; j < w; j++) + { + if (j+x < 0) continue; + if (j+x >= width) break; + + long alpha = geta(bmp->bits[int(i*ky)*bmp->width + int(j*kx)]); +// COLOR32 cl = getr(bmp->bits[int(i*ky)*bmp->width + int(j*kx)]); + COLOR32 cl = alpha ? getr(bmp->bits[int(i*ky)*bmp->width + int(j*kx)])*255/alpha : 0; +#pragma warning(push) +#pragma warning(disable: 4244) + bits[(i+y)*width + (j+x)] = (cl > 128) ? + rgba( + PU_DIV255((koef1r * cl + br)*alpha), + PU_DIV255((koef1g * cl + bg)*alpha), + PU_DIV255((koef1b * cl + bb)*alpha), + alpha): + rgba( + PU_DIV255(koef2r * cl * alpha), + PU_DIV255(koef2g * cl * alpha), + PU_DIV255(koef2b * cl * alpha), + alpha); +#pragma warning(pop) +// bits[(i+y)*width + (j+x)] = (cl > 128) ? +// rgba(koef1r * cl + br, koef1g * cl + bg, koef1b * cl + bb, geta(bmp->bits[int(i*ky)*bmp->width + int(j*kx)])): +// rgba(koef2r * cl, koef2g * cl, koef2b * cl, geta(bmp->bits[int(i*ky)*bmp->width + int(j*kx)])); + } + } +} + +void MyBitmap::BlendPart(MyBitmap *bmp, int xin, int yin, int win, int hin, int x, int y, int w, int h) +{ + if (!(bits && bmp && bmp->bits)) return; + if (!win || !hin) return; + + GdiFlush(); + + if (!w) w = win; + if (!h) h = hin; + float kx = (float)win / w; + float ky = (float)hin / h; + + if (x+w >= this->getWidth()) + w = this->getWidth() - x; + if (y+h >= this->getHeight()) + h = this->getHeight() - y; + + for (int i = 0; i < h; i++) + { + if (i+y < 0) continue; + if (i+y >= height) break; + for (int j = 0; j < w; j++) + { + if (j+x < 0) continue; + if (j+x >= width) break; + COLOR32 src = bmp->bits[int(yin+i*ky)*bmp->width + int(xin+j*kx)]; + COLOR32 dst = bits[(i+y)*width + (j+x)]; + long alpha = geta(src); + bits[(i+y)*width + (j+x)] = rgba( + getr(src)+PU_DIV255((255-alpha)*getr(dst)), + getg(src)+PU_DIV255((255-alpha)*getg(dst)), + getb(src)+PU_DIV255((255-alpha)*getb(dst)), + geta(src)+PU_DIV255((255-alpha)*geta(dst)) + ); +// bits[(i+y)*width + (j+x)] = bmp->bits[int(yin+i*ky)*bmp->width + int(xin+j*kx)]; + } + } +} + +void MyBitmap::BlendPartColorized(MyBitmap *bmp, int xin, int yin, int win, int hin, int x, int y, int w, int h, COLOR32 color) +{ + if (!(bits && bmp && bmp->bits)) return; + if (!win || !hin) return; + + GdiFlush(); + + if (!w) w = win; + if (!h) h = hin; + float kx = (float)win / w; + float ky = (float)hin / h; + + if (x+w >= this->getWidth()) + w = this->getWidth() - x; + if (y+h >= this->getHeight()) + h = this->getHeight() - y; + + // we should swap B and R channels when working with win32 COLORREF + float koef1r = (255 - getb(color)) / 128.0f; + float koef1g = (255 - getg(color)) / 128.0f; + float koef1b = (255 - getr(color)) / 128.0f; + + int br = - 255 + 2 * getb(color); + int bg = - 255 + 2 * getg(color); + int bb = - 255 + 2 * getr(color); + + float koef2r = (getb(color)) / 128.0f; + float koef2g = (getg(color)) / 128.0f; + float koef2b = (getr(color)) / 128.0f; + + for (int i = 0; i < h; i++) + { + if (i+y < 0) continue; + if (i+y >= height) break; + for (int j = 0; j < w; j++) + { + if (j+x < 0) continue; + if (j+x >= width) break; + + long alpha = geta(bmp->bits[int(yin+i*ky)*bmp->width + int(xin+j*kx)]); +// COLOR32 cl = getr(bmp->bits[int(i*ky)*bmp->width + int(j*kx)]); + COLOR32 cl = alpha ? getr(bmp->bits[int(yin+i*ky)*bmp->width + int(xin+j*kx)])*255/alpha : 0; +#pragma warning(push) +#pragma warning(disable: 4244) + COLOR32 src = (cl > 128) ? + rgba( + PU_DIV255((koef1r * cl + br)*alpha), + PU_DIV255((koef1g * cl + bg)*alpha), + PU_DIV255((koef1b * cl + bb)*alpha), + alpha): + rgba( + PU_DIV255(koef2r * cl * alpha), + PU_DIV255(koef2g * cl * alpha), + PU_DIV255(koef2b * cl * alpha), + alpha); +#pragma warning(pop) +// COLOR32 cl = getr(bmp->bits[int(i*ky)*bmp->width + int(j*kx)]); +// COLOR32 src = (cl > 128) ? +// rgba(koef1r * cl + br, koef1g * cl + bg, koef1b * cl + bb, alpha): +// rgba(koef2r * cl, koef2g * cl, koef2b * cl, alpha); + COLOR32 dst = bits[(i+y)*width + (j+x)]; +// long alpha = geta(src); + bits[(i+y)*width + (j+x)] = rgba( + getr(src)+PU_DIV255((255-alpha)*getr(dst)), + getg(src)+PU_DIV255((255-alpha)*getg(dst)), + getb(src)+PU_DIV255((255-alpha)*getb(dst)), + geta(src)+PU_DIV255((255-alpha)*geta(dst)) + ); + +/* COLOR32 src = bmp->bits[int(yin+i*ky)*bmp->width + int(xin+j*kx)]; + COLOR32 dst = bits[(i+y)*width + (j+x)]; + long alpha = geta(src); + bits[(i+y)*width + (j+x)] = rgba( + getr(src)+(255-alpha)*getr(dst)/255, + getg(src)+(255-alpha)*getg(dst)/255, + getb(src)+(255-alpha)*getb(dst)/255, + geta(src)+(255-alpha)*geta(dst)/255 + );*/ +// bits[(i+y)*width + (j+x)] = bmp->bits[int(yin+i*ky)*bmp->width + int(xin+j*kx)]; + } + } +} + +void MyBitmap::DrawPart(MyBitmap *bmp, int xin, int yin, int win, int hin, int x, int y, int w, int h) +{ + if (!(bits && bmp && bmp->bits)) return; + if (!win || !hin) return; + + GdiFlush(); + + if (!w) w = win; + if (!h) h = hin; + float kx = (float)win / w; + float ky = (float)hin / h; + + if (x+w >= this->getWidth()) + w = this->getWidth() - x; + if (y+h >= this->getHeight()) + h = this->getHeight() - y; + + for (int i = 0; i < h; i++) + { + if (i+y < 0) continue; + if (i+y >= height) break; + for (int j = 0; j < w; j++) + { + if (j+x < 0) continue; + if (j+x >= width) break; + bits[(i+y)*width + (j+x)] = bmp->bits[int(yin+i*ky)*bmp->width + int(xin+j*kx)]; + } + } +} + +void MyBitmap::DrawNoAlpha(MyBitmap *bmp, int x, int y, int w, int h) +{ + if (!(bits && bmp && bmp->bits)) return; + + GdiFlush(); + + for (int i = 0; i < bmp->height; i++) + { + if (i+y < 0) continue; + if (i+y >= height) break; + for (int j = 0; j < bmp->width; j++) + { + if (j+x < 0) continue; + if (j+x >= width) break; + bits[(i+y)*width + (j+x)] = bmp->bits[i*bmp->width + j]; + } + } +} + +static __forceinline int ReadP(long *p, int w, int h, int x, int y, int k) +{ + if (x<0) x=0; else if (x>=w) x=w-1; + if (y<0) y=0; else if (y>=h) y=h-1; + return p[(x+y*w)*4+k]; +} + +void MyBitmap::Blur(int w, int h) +{ + if ((w <= 0) || (h <= 0)) return; + + BYTE *buf_src = new BYTE[width*height*4]; + long *buf_tmp = new long[width*height*4]; + BYTE *buf_dst = (BYTE *)bits; + memcpy(buf_src, buf_dst, width*height*4); + + BYTE *src, *dst; + long *tmp; + + src = buf_src; + tmp = buf_tmp; + dst = buf_dst; + + int y; + + for (y = 0; y < height; ++y) + { + for (int x = 0; x < width; ++x) + { + for (int k = 0; k < 4; ++k) + { + int tot = src[0]; + if (x > 0) tot += tmp[-4]; + if (y > 0) tot += tmp[-width*4]; + if (x > 0 && y > 0) tot -= tmp[-(width+1)*4]; + *tmp = tot; + + ++src; + ++tmp; + } + } + } + + src = buf_src; + tmp = buf_tmp; + dst = buf_dst; + + float mul = 1.f/((w*2+1)*(h*2+1)); + for (y=0;yBlendBits((COLOR32 *)cbit, bmpColor.bmWidth, bmpColor.bmHeight, x, y, w, h); + + delete [] mbit; + delete [] cbit; + } else + { + this->saveAlpha(x,y,w,h); + DrawIconEx(this->getDC(), x, y, hic, w, h, 0, NULL, DI_NORMAL); + this->restoreAlpha(x,y,w,h); + } + + DeleteObject(info.hbmColor); + DeleteObject(info.hbmMask); +} + +//Base on code by Artem Shpynov +//from clist_modern plugin +//slightly modified and integrated to MyBitmap class +void MyBitmap::DrawText(TCHAR *str, int x, int y, int blur, int strength) +{ + SIZE sz; GetTextExtentPoint32(this->getDC(), str, lstrlen(str), &sz); + sz.cx += (blur+2)*2; sz.cy += (blur+2)*2; + x -= blur+2; y -= blur+2; + + static BYTE pbGammaWeight[256]={0}; + static BOOL bGammaWeightFilled=FALSE; + + if (!bGammaWeightFilled) + { + int i; + for(i=0;i<256;i++) + { + double f; + double gamma=(double)700/1000; + + f=(double)i/255; + f=pow(f,(1/gamma)); + + pbGammaWeight[i]=(BYTE)(255*f); + } + bGammaWeightFilled=1; + } + + MyBitmap tmp(sz.cx, sz.cy); + HFONT hfnTmp = (HFONT)SelectObject(tmp.getDC(), GetCurrentObject(this->getDC(), OBJ_FONT)); + + RECT rc; SetRect(&rc, 0, 0, sz.cx, sz.cy); + SetTextColor(tmp.getDC(), RGB(255,255,255)); + SetBkColor(tmp.getDC(), RGB(0,0,0)); + ExtTextOutA(tmp.getDC(), 0, 0, ETO_OPAQUE, &rc, "", 0, NULL); + ::DrawText(tmp.getDC(), str, lstrlen(str), &rc, DT_CENTER|DT_NOPREFIX|DT_SINGLELINE|DT_VCENTER); + SelectObject(tmp.getDC(), hfnTmp); + + GdiFlush(); + + if (blur) + { + for (int i = 0; i < sz.cy; i++) + { + COLOR32 *row_src = tmp.bits + i * tmp.width; + + for (int j = 0; j < sz.cx; j++) + { + COLOR32 cl = row_src[j]; + if (!cl) continue; + + int a1 = (getr(cl) + getg(cl) + getb(cl)) / 3; + row_src[j] = rgba(a1, a1, a1, a1); + } + } + tmp.Blur(blur, blur); + tmp.IncreaseAlpha((float)(strength ? strength : blur)); + } + + // use Get*Value for COLORREF and get* for COLOR32 + COLOR32 textColor = GetTextColor(this->getDC()); + COLOR32 r = GetRValue(textColor); + COLOR32 g = GetGValue(textColor); + COLOR32 b = GetBValue(textColor); + + int minx = max(0,-x); + int miny = max(0,-y); + int maxx = min(sz.cx, width-x); + int maxy = min(sz.cy, height-y); + + for (int i = miny; i < maxy; i++) + { + COLOR32 *row_dst = bits + (i+y) * width + x; + COLOR32 *row_src = tmp.bits + i * tmp.width; + + for (int j = minx; j < maxx; j++) + { + COLOR32 bx,rx,gx,mx; + { + bx=pbGammaWeight[getb(row_src[j])]; + gx=pbGammaWeight[getg(row_src[j])]; + rx=pbGammaWeight[getr(row_src[j])]; + } + + bx=(pbGammaWeight[bx]*(255-b)+bx*(b))/255; + gx=(pbGammaWeight[gx]*(255-g)+gx*(g))/255; + rx=(pbGammaWeight[rx]*(255-r)+rx*(r))/255; + + mx=(BYTE)(max(max(bx,rx),gx)); + + if (1) + { + bx=(bx>3):bx; + rx=(rx>3):rx; + gx=(gx>3):gx; + // reduce boldeness at white fonts + } + COLOR32 cl = row_dst[j]; + if (mx) + { + COLOR32 rrx,grx,brx; + COLOR32 rlx,glx,blx; + COLOR32 axx=geta(cl); + COLOR32 mmx=(bx+gx+rx)/3; + COLOR32 nx=mmx;;//pbGammaWeight[mx];// + { + //Normalize components to alpha level + bx=(nx*(255-axx)+bx*axx)/255; + gx=(nx*(255-axx)+gx*axx)/255; + rx=(nx*(255-axx)+rx*axx)/255; + mx=(nx*(255-axx)+mmx*axx)/255; + } + { + blx = getb(cl); + glx = getg(cl); + rlx = getr(cl); + + brx=(b-blx)*bx/255; + grx=(g-glx)*gx/255; + rrx=(r-rlx)*rx/255; + row_dst[j] = rgba(rlx+rrx, glx+grx, blx+brx, mx+(255-mx)*axx/255); + } + } + } + } +} + +// based on code by Yuriy Zaporozhets from: +// http://www.codeproject.com/gdi/coolrgn.asp?df=100&forumid=739&exp=0&select=6341 +// slightly modified to integrate with MyBitmap class. +HRGN MyBitmap::buildOpaqueRgn(int level, bool opaque) +{ + GdiFlush(); + + const int addRectsCount = 64; + int rectsCount = addRectsCount; + PRGNDATA pRgnData = (PRGNDATA)(new BYTE[sizeof(RGNDATAHEADER) + (rectsCount)*sizeof(RECT)]); + LPRECT pRects = (LPRECT)(&pRgnData->Buffer); + + memset(pRgnData, 0, sizeof(RGNDATAHEADER) + (rectsCount)*sizeof(RECT)); + pRgnData->rdh.dwSize = sizeof(RGNDATAHEADER); + pRgnData->rdh.iType = RDH_RECTANGLES; + + int first = 0; + bool wasfirst = false; + bool ismask = false; + for (int i = 0; i < height; i++) + { + int j; // we will need j after the loop! + for (j = 0; j < width; j++) + { + ismask = opaque ? (int)geta(this->getRow(i)[j]) > level : (int)geta(this->getRow(i)[j]) < level; + if (wasfirst) + { + if (!ismask) + { + SetRect(&pRects[pRgnData->rdh.nCount++], first, i, j, i+1); + if ((int)(pRgnData->rdh.nCount) >= rectsCount) + { + rectsCount += addRectsCount; + LPRGNDATA pRgnDataNew = (LPRGNDATA)(new BYTE[sizeof(RGNDATAHEADER) + (rectsCount)*sizeof(RECT)]); + memcpy(pRgnDataNew, pRgnData, sizeof(RGNDATAHEADER) + pRgnData->rdh.nCount * sizeof(RECT)); + delete pRgnData; + pRgnData = pRgnDataNew; + pRects = (LPRECT)(&pRgnData->Buffer); + } + wasfirst = false; + } + } else + if (ismask) // set wasfirst when mask is found + { + first = j; + wasfirst = true; + } + } + + if (wasfirst && ismask) + { + SetRect(&pRects[pRgnData->rdh.nCount++], first, i, j, i+1); + if ((int)(pRgnData->rdh.nCount) >= rectsCount) + { + rectsCount += addRectsCount; + LPRGNDATA pRgnDataNew = (LPRGNDATA)(new BYTE[sizeof(RGNDATAHEADER) + (rectsCount)*sizeof(RECT)]); + memcpy(pRgnDataNew, pRgnData, sizeof(RGNDATAHEADER) + pRgnData->rdh.nCount * sizeof(RECT)); + delete pRgnData; + pRgnData = pRgnDataNew; + pRects = (LPRECT)(&pRgnData->Buffer); + } + wasfirst = false; + } + + } + + HRGN hRgn = ExtCreateRegion(NULL, sizeof(RGNDATAHEADER) + pRgnData->rdh.nCount*sizeof(RECT), (LPRGNDATA)pRgnData); + delete pRgnData; + return hRgn; +} + +static int hex2dec(char hex) +{ + if ((hex >= '0') && (hex <= '9')) + return hex - '0'; + if ((hex >= 'a') && (hex <= 'f')) + return hex - 'a' + 0xa; + if ((hex >= 'A') && (hex <= 'F')) + return hex - 'A' + 0xa; + return 0; +} + +bool MyBitmap::loadFromFile_pixel(const char *fn, const char *fnAlpha) +{ + allocate(1,1); + int r, g, b, a=255; + const char *p = fn + lstrlenA("pixel:"); + r = (hex2dec(p[0]) << 4) + hex2dec(p[1]); + g = (hex2dec(p[2]) << 4) + hex2dec(p[3]); + b = (hex2dec(p[4]) << 4) + hex2dec(p[5]); + *bits = rgba(r,g,b,a); + return true; +} + +bool MyBitmap::loadFromFile_gradient(const char *fn, const char *fnAlpha) +{ + const char *p = fn + lstrlenA("gradient:"); + + if (*p == 'h') allocate(256,1); + else allocate(1,256); + + int r, g, b, a=255; + + p += 2; + r = (hex2dec(p[0]) << 4) + hex2dec(p[1]); + g = (hex2dec(p[2]) << 4) + hex2dec(p[3]); + b = (hex2dec(p[4]) << 4) + hex2dec(p[5]); + COLOR32 from = rgba(r,g,b,a); + + p += 7; + r = (hex2dec(p[0]) << 4) + hex2dec(p[1]); + g = (hex2dec(p[2]) << 4) + hex2dec(p[3]); + b = (hex2dec(p[4]) << 4) + hex2dec(p[5]); + COLOR32 to = rgba(r,g,b,a); + + for (int i = 0; i < 256; ++i) + { + bits[i] = rgba( + ((255-i) * getr(from) + i * getr(to)) / 255, + ((255-i) * getg(from) + i * getg(to)) / 255, + ((255-i) * getb(from) + i * getb(to)) / 255, + 255 + ); + } + + return true; +} + +bool MyBitmap::loadFromFile_png(const char *fn, const char *fnAlpha) +{ + if (ServiceExists(MS_PNG2DIB)) + { + HANDLE hFile, hMap = 0; + BYTE *ppMap = 0; + long cbFileSize = 0; + BITMAPINFOHEADER *pDib; + BYTE *pDibBits; + if ((hFile = CreateFileA(fn, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL)) != INVALID_HANDLE_VALUE) + if ((hMap = CreateFileMapping(hFile, NULL, PAGE_READONLY, 0, 0, NULL)) != NULL) + if ((ppMap = (BYTE*)MapViewOfFile( hMap, FILE_MAP_READ, 0, 0, 0 )) != NULL) + cbFileSize = GetFileSize(hFile, NULL); + if (cbFileSize) + { + PNG2DIB param; + param.pSource = ppMap; + param.cbSourceSize = cbFileSize; + param.pResult = &pDib; + if (CallService(MS_PNG2DIB, 0, (LPARAM)¶m)) + pDibBits = (BYTE*)(pDib+1); + else + cbFileSize = 0; + } + + if (ppMap) UnmapViewOfFile(ppMap); + if (hMap) CloseHandle(hMap); + if (hFile) CloseHandle(hFile); + + if (!cbFileSize) return false; + + BITMAPINFO *bi=(BITMAPINFO*)pDib; + BYTE *pt=(BYTE*)bi; + pt+=bi->bmiHeader.biSize; + + if (bi->bmiHeader.biBitCount != 32) + { + allocate(abs(bi->bmiHeader.biWidth), abs(bi->bmiHeader.biHeight)); + HDC hdcTmp = CreateCompatibleDC(getDC()); + HBITMAP hBitmap = CreateDIBitmap(getDC(), pDib, CBM_INIT, pDibBits, bi, DIB_PAL_COLORS); + SelectObject(hdcTmp, hBitmap); + BitBlt(this->getDC(), 0, 0, abs(bi->bmiHeader.biWidth), abs(bi->bmiHeader.biHeight), hdcTmp, 0, 0, SRCCOPY); + this->makeOpaque(); + DeleteDC(hdcTmp); + DeleteObject(hBitmap); + } else + { + allocate(abs(bi->bmiHeader.biWidth), abs(bi->bmiHeader.biHeight)); + BYTE *p2=(BYTE *)pt; + for (int y=0; ybmiHeader.biHeight; ++y) + { + BYTE *p1=(BYTE *)bits + (bi->bmiHeader.biHeight-y-1)*bi->bmiHeader.biWidth*4; + for (int x=0; xbmiHeader.biWidth; ++x) + { + p1[0]= p2[0]; + p1[1]= p2[1]; + p1[2]= p2[2]; + p1[3]= p2[3]; + p1 += 4; + p2 += 4; + } + } +// memcpy(bits, pt, bi->bmiHeader.biSizeImage); + premultipleChannels(); + } + + GlobalFree(pDib); + return true; + } else + { +// MessageBox(NULL, Translate("You need the png2dib plugin v. 0.1.3.x or later to process PNG images"), Translate("Error"), MB_OK); + return false; + } +} + +bool MyBitmap::loadFromFile_default(const char *fn, const char *fnAlpha) +{ + SIZE sz; + HBITMAP hBmpLoaded = (HBITMAP)LoadImageA(NULL, fn, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE); + if (!hBmpLoaded) + return false; + + BITMAP bm; GetObject(hBmpLoaded, sizeof(bm), &bm); + SetBitmapDimensionEx(hBmpLoaded, bm.bmWidth, bm.bmHeight, NULL); + + HDC dcTmp = CreateCompatibleDC(0); + GetBitmapDimensionEx(hBmpLoaded, &sz); + HBITMAP hBmpDcSave = (HBITMAP)SelectObject(dcTmp, hBmpLoaded); + + allocate(sz.cx, sz.cy); + BitBlt(dcBmp, 0, 0, width, height, dcTmp, 0, 0, SRCCOPY); + + DeleteObject(SelectObject(dcTmp, hBmpDcSave)); + DeleteDC(dcTmp); + + MyBitmap alpha; + if (fnAlpha && alpha.loadFromFile(fnAlpha) && + (alpha.getWidth() == width) && + (alpha.getHeight() == height) ) + { + for (int i = 0; i < width*height; i++) + bits[i] = (bits[i] & 0x00ffffff) | ( (alpha.bits[i] & 0x000000ff) << 24 ); + premultipleChannels(); + } else + { + makeOpaque(); + } + return true; +} + +bool MyBitmap::loadFromFile(const char *fn, const char *fnAlpha) +{ + if (bits) free(); + + if (!strncmp(fn, "pixel:", lstrlenA("pixel:"))) + { + return loadFromFile_pixel(fn, fnAlpha); + } else + if (!strncmp(fn, "gradient:", lstrlenA("gradient:"))) + { + return loadFromFile_gradient(fn, fnAlpha); + } else + { + char ext[5]; + memcpy(ext,fn+(strlen(fn)-4),5); + if (!lstrcmpiA(ext,".png")) + { + return loadFromFile_png(fn, fnAlpha); + } else + { + return loadFromFile_default(fn, fnAlpha); + } + } + // unreachable place + return false; +} + +void MyBitmap::allocate(int w, int h) +{ + if (dcBmp && (width == w) && (height == h)) return; + + width = w; + height = h; + + BITMAPINFO bi; + + bi.bmiHeader.biSize = sizeof(bi.bmiHeader); + bi.bmiHeader.biWidth = w; + bi.bmiHeader.biHeight = -h; + bi.bmiHeader.biPlanes = 1; + bi.bmiHeader.biBitCount = 32; + bi.bmiHeader.biCompression = BI_RGB; + + if (dcBmp) + { + DeleteObject(SelectObject(dcBmp, hBmpSave)); + DeleteDC(dcBmp); + } + + hBmp = (HBITMAP)CreateDIBSection(0, &bi, DIB_RGB_COLORS, (void **)&bits, 0, 0); + dcBmp = CreateCompatibleDC(0); + hBmpSave = (HBITMAP)SelectObject(dcBmp, hBmp); + + GdiFlush(); +} + +void MyBitmap::free() +{ + GdiFlush(); + + DeleteObject(SelectObject(dcBmp, hBmpSave)); + DeleteDC(dcBmp); + + dcBmp = 0; + hBmp = 0; + bits = 0; + width = height = 0; +} + +void MyBitmap::premultipleChannels() +{ + GdiFlush(); + + for (int i = 0; i < width*height; i++) + bits[i] = rgba(getr(bits[i])*geta(bits[i])/255, getg(bits[i])*geta(bits[i])/255, getb(bits[i])*geta(bits[i])/255, geta(bits[i])); +} -- cgit v1.2.3