]> git.imager.perl.org - imager.git/blame - win32.c
Fixed warnings for ~0 for unsigned int variables. Also a fix for a bug
[imager.git] / win32.c
CommitLineData
faa9b3e7
TC
1#include "image.h"
2#define STRICT
3#include <windows.h>
4
5/*
6=head1 NAME
7
8win32.c - implements some win32 specific code, specifically Win32 font support.
9
10=head1 SYNOPSIS
11
12 int bbox[6];
13 if (i_wf_bbox(facename, size, text, text_len, bbox)) {
14 // we have the bbox
15 }
16
17*/
18
19static void set_logfont(char *face, int size, LOGFONT *lf) {
20 memset(lf, 0, sizeof(LOGFONT));
21
22 lf->lfHeight = -size; /* character height rather than cell height */
23 lf->lfCharSet = ANSI_CHARSET;
24 lf->lfOutPrecision = OUT_TT_PRECIS;
25 lf->lfClipPrecision = CLIP_DEFAULT_PRECIS;
26 lf->lfQuality = PROOF_QUALITY;
27 strncpy(lf->lfFaceName, face, sizeof(lf->lfFaceName)-1);
28 /* NUL terminated by the memset at the top */
29}
30
31#define fixed(x) ((x).value + ((x).fract) / 65536.0)
32
33int i_wf_bbox(char *face, int size, char *text, int length, int *bbox) {
34 LOGFONT lf;
35 HFONT font, oldFont;
36 HDC dc;
37 SIZE sz;
38 TEXTMETRIC tm;
39 ABC first, last;
40 GLYPHMETRICS gm;
41 int i;
42 MAT2 mat;
43
44 set_logfont(face, size, &lf);
45 font = CreateFontIndirect(&lf);
46 if (!font)
47 return 0;
48 dc = GetDC(NULL);
49 oldFont = (HFONT)SelectObject(dc, font);
50
51#if 1
52 if (!GetTextExtentPoint32(dc, text, length, &sz)
53 || !GetTextMetrics(dc, &tm)) {
54 SelectObject(dc, oldFont);
55 ReleaseDC(NULL, dc);
56 DeleteObject(font);
57 return 0;
58 }
59 /* if there's a way to get a characters ascent/descent reliably, I can't
60 see it. GetGlyphOutline() seems to return the same size for
61 all characters.
62 */
63 bbox[1] = bbox[4] = tm.tmDescent;
64 bbox[2] = sz.cx;
65 bbox[3] = bbox[5] = tm.tmAscent;
66
67 if (GetCharABCWidths(dc, text[0], text[0], &first)
68 && GetCharABCWidths(dc, text[length-1], text[length-1], &last)) {
69 bbox[0] = first.abcA;
70 if (last.abcC < 0)
71 bbox[2] -= last.abcC;
72 }
73 else {
74 bbox[0] = 0;
75 }
76#else
77 for (i = 0; i < length; ++i) {
78 memset(&gm, 0, sizeof(gm));
79 memset(&mat, 0, sizeof(mat));
80 mat.eM11.value = 1;
81 mat.eM22.value = 1;
82 if (GetGlyphOutline(dc, GGO_METRICS, text[i], &gm, 0, NULL, &mat) != GDI_ERROR) {
83 printf("%02X: black (%d, %d) origin (%d, %d) cell(%d, %d)\n",
84 text[i], gm.gmBlackBoxX, gm.gmBlackBoxY, gm.gmptGlyphOrigin.x,
85 gm.gmptGlyphOrigin.y, gm.gmCellIncX, gm.gmCellIncY);
86 printf(" : mat [ %-8f %-8f ]\n", fixed(mat.eM11), fixed(mat.eM12));
87 printf(" [ %-8f %-8f ]\n", fixed(mat.eM21), fixed(mat.eM22));
88 }
89 else {
90 printf("Could not get metrics for '\\x%02X'\n", text[i]);
91 }
92 if (GetCharABCWidths(dc, text[i], text[i], &first)) {
93 printf("%02X: %d %d %d\n", text[i], first.abcA, first.abcB, first.abcC);
94 }
95 }
96#endif
97
98 SelectObject(dc, oldFont);
99 ReleaseDC(NULL, dc);
100 DeleteObject(font);
101
102 return 1;
103}
104
105
106/* renders the text to an in-memory RGB bitmap
107 It would be nice to render to greyscale, but Windows doesn't have
108 native greyscale bitmaps.
109 */
110LPVOID render_text(char *face, int size, char *text, int length, int aa,
111 HBITMAP *pbm, SIZE *psz, TEXTMETRIC *tm) {
112 BITMAPINFO bmi;
113 BITMAPINFOHEADER *bmih = &bmi.bmiHeader;
114 HDC dc, bmpDc;
115 LOGFONT lf;
116 HFONT font, oldFont;
117 SIZE sz;
118 HBITMAP bm, oldBm;
119 LPVOID bits;
120
121 dc = GetDC(NULL);
122 set_logfont(face, size, &lf);
123
124#ifdef ANTIALIASED_QUALITY
125 /* See KB article Q197076
126 "INFO: Controlling Anti-aliased Text via the LOGFONT Structure"
127 */
128 lf.lfQuality = aa ? ANTIALIASED_QUALITY : NONANTIALIASED_QUALITY;
129#endif
130
131 bmpDc = CreateCompatibleDC(dc);
132 if (bmpDc) {
133 font = CreateFontIndirect(&lf);
134 if (font) {
135 oldFont = SelectObject(bmpDc, font);
136 GetTextExtentPoint32(bmpDc, text, length, &sz);
137 GetTextMetrics(bmpDc, tm);
138
139 memset(&bmi, 0, sizeof(bmi));
140 bmih->biSize = sizeof(*bmih);
141 bmih->biWidth = sz.cx;
142 bmih->biHeight = sz.cy;
143 bmih->biPlanes = 1;
144 bmih->biBitCount = 24;
145 bmih->biCompression = BI_RGB;
146 bmih->biSizeImage = 0;
147 bmih->biXPelsPerMeter = 72 / 2.54 * 100;
148 bmih->biYPelsPerMeter = bmih->biXPelsPerMeter;
149 bmih->biClrUsed = 0;
150 bmih->biClrImportant = 0;
151
152 bm = CreateDIBSection(dc, &bmi, DIB_RGB_COLORS, &bits, NULL, 0);
153
154 if (bm) {
155 oldBm = SelectObject(bmpDc, bm);
156 SetTextColor(bmpDc, RGB(255, 255, 255));
157 SetBkColor(bmpDc, RGB(0, 0, 0));
158 TextOut(bmpDc, 0, 0, text, length);
159 SelectObject(bmpDc, oldBm);
160 }
161 else {
162 i_push_errorf(0, "Could not create DIB section for render: %ld",
163 GetLastError());
164 SelectObject(bmpDc, oldFont);
165 DeleteObject(font);
166 DeleteDC(bmpDc);
167 ReleaseDC(NULL, dc);
168 return NULL;
169 }
170 SelectObject(bmpDc, oldFont);
171 DeleteObject(font);
172 }
173 else {
174 i_push_errorf(0, "Could not create logical font: %ld",
175 GetLastError());
176 DeleteDC(bmpDc);
177 ReleaseDC(NULL, dc);
178 return NULL;
179 }
180 DeleteDC(bmpDc);
181 }
182 else {
183 i_push_errorf(0, "Could not create rendering DC: %ld", GetLastError());
184 ReleaseDC(NULL, dc);
185 return NULL;
186 }
187
188 ReleaseDC(NULL, dc);
189
190 *pbm = bm;
191 *psz = sz;
192
193 return bits;
194}
195
196int
197i_wf_text(char *face, i_img *im, int tx, int ty, i_color *cl, int size,
198 char *text, int len, int align, int aa) {
199 unsigned char *bits;
200 HBITMAP bm;
201 SIZE sz;
202 int line_width;
203 int x, y;
204 int ch;
205 TEXTMETRIC tm;
206 int top;
207
208 bits = render_text(face, size, text, len, aa, &bm, &sz, &tm);
209 if (!bits)
210 return 0;
211
212 line_width = sz.cx * 3;
213 line_width = (line_width + 3) / 4 * 4;
214 top = ty;
215 if (align)
216 top -= tm.tmAscent;
217
218 for (y = 0; y < sz.cy; ++y) {
219 for (x = 0; x < sz.cx; ++x) {
220 i_color pel;
221 int scale = bits[3 * x];
222 i_gpix(im, tx+x, top+sz.cy-y-1, &pel);
223 for (ch = 0; ch < im->channels; ++ch) {
224 pel.channel[ch] =
225 ((255-scale) * pel.channel[ch] + scale*cl->channel[ch]) / 255.0;
226 }
227 i_ppix(im, tx+x, top+sz.cy-y-1, &pel);
228 }
229 bits += line_width;
230 }
231 DeleteObject(bm);
232
233 return 1;
234}
235
236int
237i_wf_cp(char *face, i_img *im, int tx, int ty, int channel, int size,
238 char *text, int len, int align, int aa) {
239 unsigned char *bits;
240 HBITMAP bm;
241 SIZE sz;
242 int line_width;
243 int x, y;
244 int ch;
245 TEXTMETRIC tm;
246 int top;
247
248 bits = render_text(face, size, text, len, aa, &bm, &sz, &tm);
249 if (!bits)
250 return 0;
251
252 line_width = sz.cx * 3;
253 line_width = (line_width + 3) / 4 * 4;
254 top = ty;
255 if (align)
256 top -= tm.tmAscent;
257
258 for (y = 0; y < sz.cy; ++y) {
259 for (x = 0; x < sz.cx; ++x) {
260 i_color pel;
261 int scale = bits[3 * x];
262 i_gpix(im, tx+x, top+sz.cy-y-1, &pel);
263 pel.channel[channel] = scale;
264 i_ppix(im, tx+x, top+sz.cy-y-1, &pel);
265 }
266 bits += line_width;
267 }
268 DeleteObject(bm);
269
270 return 1;
271}