/*********************************************************************** Copyright 2002 Ben Rudiak-Gould. 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, or visit . ***********************************************************************/ #define WIN32_LEAN_AND_MEAN #include #include "DVDSubber-compile.h" #include "DVDSubber-render.h" #include extern ICompilerCallbacks* g_compiler_callbacks; template class List { T* head; public: List() { head = 0; } void add(T* t) { t->next = head; head = t; } T* begin() const { return head; } void split_after(T* t, List* other) { other->head = head; head = t->next; t->next = 0; } ~List() { T* i = begin(); while (i) { T* j = i->next; delete i; i = j; } } }; /******************************************************************** ********************************************************************/ int FontInfo::GetTextWidth(wchar_t* text, int textlen) { HDC hdc = CreateCompatibleDC(NULL); SetMapMode(hdc, MM_TEXT); HFONT hfontDefault = (HFONT)SelectObject(hdc, hfont); SIZE size; if (!GetTextExtentPoint32W(hdc, text, textlen, &size)) { throw "GetTextExtentPoint32W failed"; } SelectObject(hdc, hfontDefault); DeleteDC(hdc); return size.cx; } FontInfo::~FontInfo() { DeleteObject((HFONT)hfont); } /******************************************************************** ********************************************************************/ List saved_fonts; int largest_height = 1; int CALLBACK EnumFontsProc(CONST LOGFONT*, CONST TEXTMETRIC*, DWORD, LPARAM pbfound) { *(bool*)pbfound = true; return 0; } FontInfo* LoadFont(const wchar_t* name, int size, bool bold, bool italic) { for (FontInfo* i = saved_fonts.begin(); i; i = i->next) { if (i->size == size && i->bold == bold && i->italic == italic && wcscmp(i->name, name)==0) return i; } HDC hdc = CreateCompatibleDC(NULL); SetMapMode(hdc, MM_TEXT); //printf("point size %d -> %d\n", size, MulDiv(size, GetDeviceCaps(hdc, LOGPIXELSY), 72)); HFONT hfont = 0; char dbname[256]; int len = WideCharToMultiByte(CP_ACP, 0, name, -1, dbname, sizeof(dbname), NULL, NULL); if (len > 0 && len <= sizeof(dbname)) { bool font_exists = false; EnumFonts(hdc, dbname, EnumFontsProc, (LPARAM)&font_exists); if (!font_exists) { char warnbuf[512]; wsprintf(warnbuf, "A font in this script (%s) is not installed on this system.", dbname); g_compiler_callbacks->Warning(warnbuf); g_compiler_callbacks->Warning("A different (hopefully similar) font will be substituted."); } hfont = CreateFont(-size, 0, 0, 0, bold ? FW_BOLD : FW_NORMAL, italic, FALSE, FALSE, DEFAULT_CHARSET, OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS, DEFAULT_QUALITY, FF_DONTCARE | DEFAULT_PITCH, dbname); } if (hfont == 0) { throw "CreateFont failed"; } FontInfo* fi = new FontInfo; wcscpy(fi->name, name); fi->size = size; fi->bold = bold; fi->italic = italic; fi->hfont = hfont; HFONT hfontDefault = (HFONT)SelectObject(hdc, fi->hfont); TEXTMETRIC tm; GetTextMetrics(hdc, &tm); fi->height = tm.tmHeight; if (tm.tmHeight > largest_height) largest_height = tm.tmHeight; fi->ascent = tm.tmAscent; fi->external_leading = tm.tmExternalLeading; static wchar_t space = 32; fi->width_of_space = fi->GetTextWidth(&space, 1); saved_fonts.add(fi); SelectObject(hdc, hfontDefault); DeleteDC(hdc); return fi; } /******************************************************************** ********************************************************************/ enum { BMPWIDTH = 800 }; unsigned dib_height = 0; HBITMAP dib; unsigned char* dib_bits; unsigned char* shadow_bits; void RenderText( const wchar_t* text, FontInfo* font, unsigned char textcolor, unsigned char halocolor, unsigned char* buf, int width, int height, int xstride, int ystride, int left, int top) { HDC hdc = CreateCompatibleDC(NULL); HFONT hfontDefault = (HFONT)SelectObject(hdc, font->hfont); if (largest_height + 4 > dib_height) { if (dib != 0) { DeleteObject(dib); } delete[] shadow_bits; dib_height = largest_height + 4; static struct { BITMAPINFOHEADER bih; RGBQUAD clr[2]; } b; b.bih.biSize = sizeof(BITMAPINFOHEADER); b.bih.biWidth = BMPWIDTH; b.bih.biHeight = dib_height; b.bih.biBitCount = 1; b.bih.biPlanes = 1; b.bih.biCompression = BI_RGB; b.bih.biXPelsPerMeter = 0; b.bih.biYPelsPerMeter = 0; b.bih.biClrUsed = 2; b.bih.biClrImportant = 2; b.clr[0].rgbBlue = b.clr[0].rgbGreen = b.clr[0].rgbRed = 0; b.clr[1].rgbBlue = b.clr[1].rgbGreen = b.clr[1].rgbRed = 255; dib = CreateDIBSection( hdc, (BITMAPINFO *)&b, DIB_RGB_COLORS, (void**)&dib_bits, NULL, 0); shadow_bits = new unsigned char[BMPWIDTH/8 * dib_height]; } memset(dib_bits, 0, BMPWIDTH/8 * dib_height); HBITMAP hbmDefault = (HBITMAP)SelectObject(hdc, dib); SetMapMode(hdc, MM_TEXT); SetTextAlign(hdc, TA_TOP | TA_LEFT /*| TA_RTLREADING*/); SetTextColor(hdc, 0xffffff); SetBkColor(hdc, 0); if (!TextOutW(hdc, (left & 7) + 8, 2, text, lstrlenW(text))) { throw "TextOut failed"; } left &= ~7; SelectObject(hdc, hbmDefault); SelectObject(hdc, hfontDefault); DeleteDC(hdc); memset(shadow_bits, 0, BMPWIDTH/8 * dib_height); for (int q = BMPWIDTH/8 * 2; q < BMPWIDTH/8 * (dib_height - 2); ++q) { unsigned char x = dib_bits[q]; unsigned char x3 = x | (x<<1) | (x>>1); unsigned char x5 = x3 | (x3<<1) | (x3>>1); unsigned char x3a = x >> 7; unsigned char x3b = x << 7; unsigned char x5a = (x >> 6) | (x >> 7); unsigned char x5b = (x << 6) | (x << 7); shadow_bits[q + BMPWIDTH/8 * -2 -1] |= x3a; shadow_bits[q + BMPWIDTH/8 * -2 ] |= x3; shadow_bits[q + BMPWIDTH/8 * -2 +1] |= x3b; shadow_bits[q + BMPWIDTH/8 * -1 -1] |= x5a; shadow_bits[q + BMPWIDTH/8 * -1 ] |= x5; shadow_bits[q + BMPWIDTH/8 * -1 +1] |= x5b; shadow_bits[q + BMPWIDTH/8 * 0 -1] |= x5a; shadow_bits[q + BMPWIDTH/8 * 0 ] |= x5; shadow_bits[q + BMPWIDTH/8 * 0 +1] |= x5b; shadow_bits[q + BMPWIDTH/8 * +1 -1] |= x5a; shadow_bits[q + BMPWIDTH/8 * +1 ] |= x5; shadow_bits[q + BMPWIDTH/8 * +1 +1] |= x5b; shadow_bits[q + BMPWIDTH/8 * +2 -1] |= x3a; shadow_bits[q + BMPWIDTH/8 * +2 ] |= x3; shadow_bits[q + BMPWIDTH/8 * +2 +1] |= x3b; } int y_top = dib_height - 1; for (int y=0; yheight + 4; ++y) { int yy = y + top - 2; if (yy < 0 || yy >= height) continue; for (int x = 0; x < BMPWIDTH/8; ++x) { unsigned char textbits = dib_bits[(y_top - y) * BMPWIDTH/8 + x]; unsigned char halobits = shadow_bits[(y_top - y) * BMPWIDTH/8 + x]; if ((textbits | halobits) == 0) continue; int xx = x*8 + left - 8; if (xx < 0 || xx > width-8) continue; unsigned char* p = &buf[yy * ystride + xx * xstride]; for (int bit = 0; bit < 8; ++bit) { if (textbits & (128 >> bit)) { p[bit * xstride] = textcolor; } else if (halobits & (128 >> bit)) { p[bit * xstride] = halocolor; } } } } }