8 win32.c - implements some win32 specific code, specifically Win32 font support.
13 if (i_wf_bbox(facename, size, text, text_len, bbox)) {
16 i_wf_text(face, im, tx, ty, cl, size, text, len, align, aa);
17 i_wf_cp(face, im, tx, ty, channel, size, text, len, align, aa)
21 An Imager interface to font output using the Win32 GDI.
28 #define fixed(x) ((x).value + ((x).fract) / 65536.0)
30 static void set_logfont(char *face, int size, LOGFONT *lf);
32 static LPVOID render_text(char *face, int size, char *text, int length, int aa,
33 HBITMAP *pbm, SIZE *psz, TEXTMETRIC *tm);
36 =item i_wf_bbox(face, size, text, length, bbox)
38 Calculate a bounding box for the text.
43 int i_wf_bbox(char *face, int size, char *text, int length, int *bbox) {
54 set_logfont(face, size, &lf);
55 font = CreateFontIndirect(&lf);
59 oldFont = (HFONT)SelectObject(dc, font);
62 if (!GetTextExtentPoint32(dc, text, length, &sz)
63 || !GetTextMetrics(dc, &tm)) {
64 SelectObject(dc, oldFont);
69 /* if there's a way to get a characters ascent/descent reliably, I can't
70 see it. GetGlyphOutline() seems to return the same size for
73 bbox[1] = bbox[4] = tm.tmDescent;
75 bbox[3] = bbox[5] = tm.tmAscent;
77 if (GetCharABCWidths(dc, text[0], text[0], &first)
78 && GetCharABCWidths(dc, text[length-1], text[length-1], &last)) {
87 for (i = 0; i < length; ++i) {
88 memset(&gm, 0, sizeof(gm));
89 memset(&mat, 0, sizeof(mat));
92 if (GetGlyphOutline(dc, GGO_METRICS, text[i], &gm, 0, NULL, &mat) != GDI_ERROR) {
93 printf("%02X: black (%d, %d) origin (%d, %d) cell(%d, %d)\n",
94 text[i], gm.gmBlackBoxX, gm.gmBlackBoxY, gm.gmptGlyphOrigin.x,
95 gm.gmptGlyphOrigin.y, gm.gmCellIncX, gm.gmCellIncY);
96 printf(" : mat [ %-8f %-8f ]\n", fixed(mat.eM11), fixed(mat.eM12));
97 printf(" [ %-8f %-8f ]\n", fixed(mat.eM21), fixed(mat.eM22));
100 printf("Could not get metrics for '\\x%02X'\n", text[i]);
102 if (GetCharABCWidths(dc, text[i], text[i], &first)) {
103 printf("%02X: %d %d %d\n", text[i], first.abcA, first.abcB, first.abcC);
108 SelectObject(dc, oldFont);
116 =item i_wf_text(face, im, tx, ty, cl, size, text, len, align, aa)
118 Draws the text in the given color.
124 i_wf_text(char *face, i_img *im, int tx, int ty, i_color *cl, int size,
125 char *text, int len, int align, int aa) {
135 bits = render_text(face, size, text, len, aa, &bm, &sz, &tm);
139 line_width = sz.cx * 3;
140 line_width = (line_width + 3) / 4 * 4;
145 for (y = 0; y < sz.cy; ++y) {
146 for (x = 0; x < sz.cx; ++x) {
148 int scale = bits[3 * x];
149 i_gpix(im, tx+x, top+sz.cy-y-1, &pel);
150 for (ch = 0; ch < im->channels; ++ch) {
152 ((255-scale) * pel.channel[ch] + scale*cl->channel[ch]) / 255.0;
154 i_ppix(im, tx+x, top+sz.cy-y-1, &pel);
164 =item i_wf_cp(face, im, tx, ty, channel, size, text, len, align, aa)
166 Draws the text in the given channel.
172 i_wf_cp(char *face, i_img *im, int tx, int ty, int channel, int size,
173 char *text, int len, int align, int aa) {
183 bits = render_text(face, size, text, len, aa, &bm, &sz, &tm);
187 line_width = sz.cx * 3;
188 line_width = (line_width + 3) / 4 * 4;
193 for (y = 0; y < sz.cy; ++y) {
194 for (x = 0; x < sz.cx; ++x) {
196 int scale = bits[3 * x];
197 i_gpix(im, tx+x, top+sz.cy-y-1, &pel);
198 pel.channel[channel] = scale;
199 i_ppix(im, tx+x, top+sz.cy-y-1, &pel);
211 =head1 INTERNAL FUNCTIONS
215 =item set_logfont(face, size, lf)
217 Fills in a LOGFONT structure with reasonable defaults.
222 static void set_logfont(char *face, int size, LOGFONT *lf) {
223 memset(lf, 0, sizeof(LOGFONT));
225 lf->lfHeight = -size; /* character height rather than cell height */
226 lf->lfCharSet = DEFAULT_CHARSET;
227 lf->lfOutPrecision = OUT_TT_PRECIS;
228 lf->lfClipPrecision = CLIP_DEFAULT_PRECIS;
229 lf->lfQuality = PROOF_QUALITY;
230 strncpy(lf->lfFaceName, face, sizeof(lf->lfFaceName)-1);
231 /* NUL terminated by the memset at the top */
235 =item render_text(face, size, text, length, aa, pbm, psz, tm)
237 renders the text to an in-memory RGB bitmap
239 It would be nice to render to greyscale, but Windows doesn't have
240 native greyscale bitmaps.
244 static LPVOID render_text(char *face, int size, char *text, int length, int aa,
245 HBITMAP *pbm, SIZE *psz, TEXTMETRIC *tm) {
247 BITMAPINFOHEADER *bmih = &bmi.bmiHeader;
256 set_logfont(face, size, &lf);
258 #ifdef ANTIALIASED_QUALITY
259 /* See KB article Q197076
260 "INFO: Controlling Anti-aliased Text via the LOGFONT Structure"
262 lf.lfQuality = aa ? ANTIALIASED_QUALITY : NONANTIALIASED_QUALITY;
265 bmpDc = CreateCompatibleDC(dc);
267 font = CreateFontIndirect(&lf);
269 oldFont = SelectObject(bmpDc, font);
270 GetTextExtentPoint32(bmpDc, text, length, &sz);
271 GetTextMetrics(bmpDc, tm);
273 memset(&bmi, 0, sizeof(bmi));
274 bmih->biSize = sizeof(*bmih);
275 bmih->biWidth = sz.cx;
276 bmih->biHeight = sz.cy;
278 bmih->biBitCount = 24;
279 bmih->biCompression = BI_RGB;
280 bmih->biSizeImage = 0;
281 bmih->biXPelsPerMeter = 72 / 2.54 * 100;
282 bmih->biYPelsPerMeter = bmih->biXPelsPerMeter;
284 bmih->biClrImportant = 0;
286 bm = CreateDIBSection(dc, &bmi, DIB_RGB_COLORS, &bits, NULL, 0);
289 oldBm = SelectObject(bmpDc, bm);
290 SetTextColor(bmpDc, RGB(255, 255, 255));
291 SetBkColor(bmpDc, RGB(0, 0, 0));
292 TextOut(bmpDc, 0, 0, text, length);
293 SelectObject(bmpDc, oldBm);
296 i_push_errorf(0, "Could not create DIB section for render: %ld",
298 SelectObject(bmpDc, oldFont);
304 SelectObject(bmpDc, oldFont);
308 i_push_errorf(0, "Could not create logical font: %ld",
317 i_push_errorf(0, "Could not create rendering DC: %ld", GetLastError());
333 Should really use a structure so we can set more attributes.
339 Tony Cook <tony@develop-help.com>