📄 dvdsubber-render.cpp
字号:
/***********************************************************************
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 <http://www.gnu.org/copyleft/gpl.html>.
***********************************************************************/
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#include "DVDSubber-compile.h"
#include "DVDSubber-render.h"
#include <stdio.h>
extern ICompilerCallbacks* g_compiler_callbacks;
template<class T>
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<T>* 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<FontInfo> 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; y<font->height + 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;
}
}
}
}
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -