summaryrefslogtreecommitdiff
path: root/plugins/Popup/src/bitmap_funcs.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'plugins/Popup/src/bitmap_funcs.cpp')
-rw-r--r--plugins/Popup/src/bitmap_funcs.cpp1019
1 files changed, 1019 insertions, 0 deletions
diff --git a/plugins/Popup/src/bitmap_funcs.cpp b/plugins/Popup/src/bitmap_funcs.cpp
new file mode 100644
index 0000000000..4cb013a378
--- /dev/null
+++ b/plugins/Popup/src/bitmap_funcs.cpp
@@ -0,0 +1,1019 @@
+/*
+Popup Plus plugin for Miranda IM
+
+Copyright © 2002 Luca Santarelli,
+ © 2004-2007 Victor Pavlychko
+ © 2010 MPK
+ © 2010 Merlin_de
+
+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.
+
+===============================================================================
+
+File name : $HeadURL: http://svn.miranda.im/mainrepo/popup/trunk/src/bitmap_funcs.cpp $
+Revision : $Revision: 1627 $
+Last change on : $Date: 2010-06-29 10:34:46 +0300 (Вт, 29 июн 2010) $
+Last change by : $Author: Merlin_de $
+
+===============================================================================
+*/
+
+#include "headers.h"
+#include "bitmap_funcs.h"
+
+#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::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;
+ if (!w || !h)
+ return;
+ if (x < 0 || y < 0)
+ return;
+
+ 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;
+ 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;
+ 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.0;
+ float koef1g = (255 - getg(color)) / 128.0;
+ float koef1b = (255 - getr(color)) / 128.0;
+
+ int br = - 255 + 2 * getb(color);
+ int bg = - 255 + 2 * getg(color);
+ int bb = - 255 + 2 * getr(color);
+
+ float koef2r = (getb(color)) / 128.0;
+ float koef2g = (getg(color)) / 128.0;
+ float koef2b = (getr(color)) / 128.0;
+
+ 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.0;
+ float koef1g = (255 - getg(color)) / 128.0;
+ float koef1b = (255 - getr(color)) / 128.0;
+
+ int br = - 255 + 2 * getb(color);
+ int bg = - 255 + 2 * getg(color);
+ int bb = - 255 + 2 * getr(color);
+
+ float koef2r = (getb(color)) / 128.0;
+ float koef2g = (getg(color)) / 128.0;
+ float koef2b = (getr(color)) / 128.0;
+
+ 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.0;
+ float koef1g = (255 - getg(color)) / 128.0;
+ float koef1b = (255 - getr(color)) / 128.0;
+
+ int br = - 255 + 2 * getb(color);
+ int bg = - 255 + 2 * getg(color);
+ int bb = - 255 + 2 * getr(color);
+
+ float koef2r = (getb(color)) / 128.0;
+ float koef2g = (getg(color)) / 128.0;
+ float koef2b = (getr(color)) / 128.0;
+
+ 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];
+ }
+ }
+}
+
+void MyBitmap::DrawIcon(HICON hic, int x, int y, int w, int h)
+{
+ GdiFlush();
+
+ ICONINFO info;
+ GetIconInfo(hic, &info);
+
+ BITMAP bmpColor, bmpMask;
+ GetObject(info.hbmMask, sizeof(bmpMask), &bmpMask);
+ GetObject(info.hbmColor, sizeof(bmpColor), &bmpColor);
+
+ if (!w) w = abs(bmpMask.bmWidth);
+ if (!h) h = abs(bmpMask.bmHeight);
+
+ if (bmpColor.bmBitsPixel == 32)
+ {
+ if ((w != abs(bmpMask.bmWidth)) || (h != abs(bmpMask.bmHeight)))
+ {
+ DeleteObject(info.hbmColor);
+ DeleteObject(info.hbmMask);
+ HICON hicTmp = (HICON)CopyImage(hic,IMAGE_ICON,w,h,LR_COPYFROMRESOURCE);
+ GetIconInfo(hicTmp, &info);
+ GetObject(info.hbmMask, sizeof(bmpMask), &bmpMask);
+ GetObject(info.hbmColor, sizeof(bmpColor), &bmpColor);
+ DestroyIcon(hicTmp);
+ }
+
+ BYTE *cbit = new BYTE[bmpColor.bmWidthBytes*bmpColor.bmHeight];
+ BYTE *mbit = new BYTE[bmpMask.bmWidthBytes*bmpMask.bmHeight];
+ GetBitmapBits(info.hbmColor, bmpColor.bmWidthBytes*bmpColor.bmHeight, cbit);
+ GetBitmapBits(info.hbmMask, bmpMask.bmWidthBytes*bmpMask.bmHeight, mbit);
+
+ for (int i = 0; i < bmpColor.bmHeight; i++)
+ {
+ for (int j = 0; j < bmpColor.bmWidth; j++)
+ {
+ BYTE *pixel = cbit + i*bmpColor.bmWidthBytes + j*4;
+ if (!pixel[3])
+ {
+ pixel[3] = (*(mbit + i*bmpMask.bmWidthBytes + j*bmpMask.bmBitsPixel/8) & (1<<(7-j%8))) ? 0 : 255;
+ }
+
+ if (pixel[3] != 255)
+ {
+ pixel[0] = PU_DIV255(pixel[0] * pixel[3]);
+ pixel[1] = PU_DIV255(pixel[1] * pixel[3]);
+ pixel[2] = PU_DIV255(pixel[2] * pixel[3]);
+ }
+ }
+ }
+
+ this->BlendBits((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);
+}
+
+void MyBitmap::Draw_TextA(char *str, int x, int y)
+{
+ GdiFlush();
+
+ SIZE sz; GetTextExtentPoint32A(this->getDC(), str, lstrlenA(str), &sz);
+ RECT rc; SetRect(&rc, x, y, x+10000, y+10000);
+ this->saveAlpha(x-2,y-2,sz.cx+2,sz.cy+2);
+ ::DrawTextA(this->getDC(), str, (int)strlen(str), &rc, DT_LEFT | DT_TOP | DT_SINGLELINE | DT_NOPREFIX);
+ this->restoreAlpha(x-2,y-2,sz.cx+2,sz.cy+2);
+ //(x,y,sz.cx,sz.cy);
+}
+
+void MyBitmap::Draw_TextW(WCHAR *str, int x, int y)
+{
+#if defined(_UNICODE)
+ SIZE sz; GetTextExtentPoint32W(this->getDC(), str, lstrlenW(str), &sz);
+ RECT rc; SetRect(&rc, x, y, x+10000, y+10000);
+ this->saveAlpha(x,y,sz.cx,sz.cy);
+ DrawTextW(this->getDC(), str, lstrlenW(str), &rc, DT_LEFT | DT_TOP | DT_SINGLELINE | DT_NOPREFIX);
+ this->restoreAlpha(x,y,sz.cx,sz.cy);
+#else
+ if (MyGetTextExtentPoint32W && MyDrawTextW)
+ {
+ SIZE sz; MyGetTextExtentPoint32W(this->getDC(), str, lstrlenW(str), &sz);
+ RECT rc; SetRect(&rc, x, y, x+10000, y+10000);
+ this->saveAlpha(x,y,sz.cx,sz.cy);
+ MyDrawTextW(this->getDC(), str, lstrlenW(str), &rc, DT_LEFT | DT_TOP | DT_SINGLELINE | DT_NOPREFIX);
+ this->restoreAlpha(x,y,sz.cx,sz.cy);
+ }
+#endif
+}
+
+// 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 ? geta(this->getRow(i)[j]) > (DWORD)level : geta(this->getRow(i)[j]) < (DWORD)level;
+ if (wasfirst)
+ {
+ if (!ismask)
+ {
+ SetRect(&pRects[pRgnData->rdh.nCount++], first, i, j, i+1);
+ if (pRgnData->rdh.nCount >= (DWORD) 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 (pRgnData->rdh.nCount >= (DWORD) 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)&param))
+ 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; y<bi->bmiHeader.biHeight; ++y)
+ {
+ BYTE *p1=(BYTE *)bits + (bi->bmiHeader.biHeight-y-1)*bi->bmiHeader.biWidth*4;
+ for (int x=0; x<bi->bmiHeader.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
+ {
+// MSGERROR(TranslateT("You need the png2dib plugin v. 0.1.3.x or later to process PNG images");
+ 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)
+{
+ 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]));
+}