Project

General

Profile

get-text-metrics.p

Roger Borrello, 03/18/2022 09:24 AM

Download (10.5 KB)

 
1
/*
2
** This program is free software: you can redistribute it and/or modify
3
** it under the terms of the GNU Affero General Public License as
4
** published by the Free Software Foundation, either version 3 of the
5
** License, or (at your option) any later version.
6
**
7
** This program is distributed in the hope that it will be useful,
8
** but WITHOUT ANY WARRANTY; without even the implied warranty of
9
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
10
** GNU Affero General Public License for more details.
11
**
12
** You may find a copy of the GNU Affero GPL version 3 at the following
13
** location: https://www.gnu.org/licenses/agpl-3.0.en.html
14
** 
15
** Additional terms under GNU Affero GPL version 3 section 7:
16
** 
17
**   Under Section 7 of the GNU Affero GPL version 3, the following additional
18
**   terms apply to the works covered under the License.  These additional terms
19
**   are non-permissive additional terms allowed under Section 7 of the GNU
20
**   Affero GPL version 3 and may not be removed by you.
21
** 
22
**   0. Attribution Requirement.
23
** 
24
**     You must preserve all legal notices or author attributions in the covered
25
**     work or Appropriate Legal Notices displayed by works containing the covered
26
**     work.  You may not remove from the covered work any author or developer
27
**     credit already included within the covered work.
28
** 
29
**   1. No License To Use Trademarks.
30
** 
31
**     This license does not grant any license or rights to use the trademarks
32
**     Golden Code, FWD, any Golden Code or FWD logo, or any other trademarks
33
**     of Golden Code Development Corporation. You are not authorized to use the
34
**     name Golden Code, FWD, or the names of any author or contributor, for
35
**     publicity purposes without written authorization.
36
** 
37
**   2. No Misrepresentation of Affiliation.
38
** 
39
**     You may not represent yourself as Golden Code Development Corporation or FWD.
40
** 
41
**     You may not represent yourself for publicity purposes as associated with
42
**     Golden Code Development Corporation, FWD, or any author or contributor to
43
**     the covered work, without written authorization.
44
** 
45
**   3. No Misrepresentation of Source or Origin.
46
** 
47
**     You may not represent the covered work as solely your work.  All modified
48
**     versions of the covered work must be marked in a reasonable way to make it
49
**     clear that the modified work is not originating from Golden Code Development
50
**     Corporation or FWD.  All modified versions must contain the notices of
51
**     attribution required in this license.
52
*/
53
/*
54
Each line in the text file represents a text (case-sensitive) for which the metrics will be 
55
captured.  Metrics will be computed for each font in the font file (and combinations of its size
56
and attributes), each text being set one per line.
57

    
58
Each line in the font file has this format: name,size,bold,italic,underline.
59
where:".
60
- name: is the font name (case insensitive)
61
- size: is the font size, integer. if not specified, metrics for 1 to max-size are captured
62
- bold: true if the bold metrics are captured. false otherwise
63
- italic: true if the italic metrics are captured. false otherwise
64
- underline: true if the underline metrics are captured. false otherwise
65

    
66
If any of the bold/italic/underline flags are missing, metrics for flag set/unset are captured.
67
*/
68

    
69
def var maxSize as int init 20.
70
def stream fnames.
71
def stream flines.
72
def stream frpt.
73
def var showdpiwarning as log init true.
74
def var fontFile as char init "font-list.txt".
75
def var textFile as char init "ui_strings.txt".
76

    
77
message "Enter the maximum font size (<= 1638):" update maxSize.
78
message "Enter the file name with the font list:" update fontFile format "x(32)".
79
message "Enter the file name with the text list:" update textFile format "x(32)".
80

    
81
file-info:file-name = fontFile.
82
if file-info:file-type = ? then do:
83
   message "File" fontFile "does not exist or is not accessible".
84
   return.
85
end.
86

    
87
file-info:file-name = textFile.
88
if file-info:file-type = ? then do:
89
   message "File" textFile "does not exist or is not accessible".
90
   return.
91
end.
92

    
93
procedure CreateFontIndirectA external "gdi32".
94
   def input param lplf as long.
95
   def return param hfont as long.
96
end.
97

    
98
procedure DeleteObject external "gdi32".
99
   def input param hgdiobj as long.
100
   def return param res as long.
101
end.
102

    
103
procedure SelectObject external "gdi32".
104
   def input param hdc as long.
105
   def input param hgdiobj as long.
106
   def return param res as long.
107
end.
108

    
109
procedure GetTextMetricsA external "gdi32".
110
   def input param hdc as long.
111
   def input param lptm as long.
112
   def return param returnvalue as long.
113
end.
114

    
115
procedure GetTextExtentPointA external "gdi32".
116
   def input param hdc as long.
117
   def input param lpctstr as long.
118
   def input param sz as long.
119
   def input param lsz as long.
120
   def return param returnvalue as long.
121
end.
122

    
123
procedure GetDC external "user32.dll".
124
   def input param ihwnd as long.
125
   def return param hdc as long.
126
end.
127

    
128
procedure ReleaseDC external "user32.dll".
129
   def input param ihwnd as long.
130
   def input param hdc as long.
131
   def return param res as long.
132
end.
133

    
134
procedure GetDeviceCaps external "gdi32".
135
   def input param hdc as long.
136
   def input param nindex as long.
137
   def return param res as long.
138
end.
139

    
140
procedure getMetrics.
141
   def input param line as char.
142
   def input param fontname as char.
143
   def input param fontsize as int.
144
   def input-output param lp as memptr.
145
   def input param fbold as log.
146
   def input param fitalic as log.
147
   def input param funderline as log.
148

    
149
   def var res as int.
150
   def var hdc as integer.
151
   def var dpi as int.
152
   def var LOGPIXELSY as int init 90.
153
   def var err as log init false.
154
   
155
   run GetDc(input current-window:hwnd, output hdc).
156

    
157
   /* get DPI */
158
   run GetDeviceCaps(input hdc, input LOGPIXELSY, output dpi).
159
   if showdpiwarning and dpi <> 96
160
   then do:
161
      message "DPI is" dpi "instead of 96!" view-as alert-box.
162
      showdpiwarning = false.
163
   end.
164
   
165
   /* create font */
166
   def var hfont as int64.
167
   def var lplf as memptr.
168
   set-size(lplf) = 5 * 4 + 8 * 1 + 1 * 32.
169
   def var i as int.
170
   do i = 1 to get-size(lplf):
171
     put-byte(lplf, i) = 0.
172
   end.
173
   put-long(lplf, (1 - 1) * 4 + 1) = -1 * int64(round(fontsize * dpi / 72.0, 2)).
174
   put-long(lplf, (5 - 1) * 4 + 1) = (if fbold then 700 else 0).
175
   put-byte(lplf, 5 * 4 + 1) = (if fitalic then 1 else 0).
176
   put-byte(lplf, 5 * 4 + 2) = (if funderline then 1 else 0).
177
   put-string(lplf, 5 * 4 + 8 + 1) = fontname.
178
   run CreateFontIndirectA(input get-pointer-value(lplf), output hfont).
179

    
180
   /* select font */
181
   def var foohdc as integer.
182
   run SelectObject(input hdc, input hfont, output foohdc).
183

    
184
   /* write string */
185
   def var lpstr as memptr.
186
   set-size(lpstr) = length(line) + 1.
187
   put-string(lpstr, 1) = line.
188

    
189
   /* get metrics */
190
   set-size(lp) = 2 * 4.
191
   run GetTextExtentPointA(input hdc, input get-pointer-value(lpstr), input length(line), input get-pointer-value(lp), output res).
192
   if res = 0 then err = yes.
193

    
194
   /* delete hfont */
195
   run DeleteObject(input hfont, output res).
196
   if res = 0 then err = yes.
197

    
198
   run ReleaseDC(input current-window:hwnd, input hdc, output res).
199
   if res = 0 then err = yes.
200
   
201
   /* delete the lplf */
202
   set-size(lplf) = 0.
203
   /* delete the lpstr */
204
   set-size(lpstr) = 0.
205
   
206
   if err
207
   then do:
208
      message "GetTextMetrics failed for" fontname fontsize ". Memory leak?".
209
      quit.
210
   end.
211
   
212
end.
213

    
214
procedure recordMetrics.
215
   def input param line as char.
216
   def input param fname as char.
217
   def input param sz as int.
218
   def input param fbold as log.
219
   def input param fitalic as log.
220
   def input param funderline as log.
221

    
222
   def var lp as memptr.
223
   def var h as int.
224
   def var w as int.
225

    
226
   run getMetrics(line, fname, sz, input-output lp, fbold, fitalic, funderline).
227
   w = get-long(lp, 1).
228
   h = get-long(lp, 1 + 4).
229

    
230
   put stream frpt unformatted space(6)
231
   '<font name="' fname '" '
232
         'size="' sz '" '
233
         'bold="' trim(string(fbold, "true/false")) '" '
234
         'italic="' trim(string(fitalic, "true/false")) '" '
235
         'underline="' trim(string(funderline, "true/false")) '" '
236
         'width="' w '" '
237
         'height="' h '"/>'  skip.
238

    
239
   /* delete the lp */
240
   set-size(lp) = 0.
241
end.
242

    
243
def var line as char.
244
def var fname as char.
245
def var sz as int.
246
def var fxmlname as char.
247
fxmlname = "text-metrics.xml".
248

    
249
form fname label "Font Name" format "x(32)" line label "Line" sz label "Size" with frame fstate down.
250

    
251
output stream frpt to value(fxmlname).
252
input stream flines from value(textFile).
253

    
254
put stream frpt unformatted '<?xml version="1.0" encoding="UTF-8"?>' skip.
255
put stream frpt unformatted '<!DOCTYPE text-list SYSTEM "text-metrics.dtd">' skip.
256
put stream frpt unformatted "<text-list>" skip.
257

    
258
repeat:
259
   import stream flines unformatted line no-error.
260
   if error-status:error then leave.
261

    
262
   def var xline as char.
263
   xline = line.
264
   xline = replace(xline, '&', "&amp;").
265
   xline = replace(xline, '"', "&quot;").
266
   xline = replace(xline, "'", "&apos;").
267
   xline = replace(xline, '<', "&lt;").
268
   xline = replace(xline, '>', "&gt;").
269

    
270
   put stream frpt unformatted space(3) '<text value="' xline '">' skip.
271

    
272
   input stream fnames from value(fontFile).
273

    
274
   repeat:
275
     def var fsize as int.
276
     def var fbold as log.
277
     def var fitalic as log.
278
     def var funder as log.
279

    
280
     fname = ?.
281
     fsize = ?.
282
     fbold = ?.
283
     fitalic = ?.
284
     funder = ?.
285
     
286
     import stream fnames delimiter "," fname fsize fbold fitalic funder no-error.
287
     if error-status:error then leave.
288

    
289
     do sz = (if fsize = ? or fsize = 0 then 1 else fsize) to (if fsize = ? or fsize = 0 then maxSize else fsize):
290
       display fname line sz with frame fstate.
291

    
292
       def var i as int.
293
       do i = 1 to 8:
294
          def var cbold as log.
295
          def var citalic as log.
296
          def var cunder as log.
297

    
298
          cbold = (i > 4).
299
          citalic = (i = 3 or i = 4 or i = 7 or i = 8).
300
          cunder = i mod 2 = 0.
301

    
302
          if (fbold   = ? or fbold   = cbold)  and
303
             (fitalic = ? or fitalic = citalic)and
304
             (funder  = ? or funder  = cunder)
305
          then run recordMetrics(line, fname, sz, cbold, citalic, cunder).
306
       end.
307
     end.
308

    
309
     down with frame fstate.
310
     if frame-line(fstate) = frame-down(fstate)
311
     then up frame-down(fstate) - 1 with frame fstate.
312

    
313
     /* force a flush */
314
     output stream frpt close.
315
     output stream frpt to value(fxmlname) append.
316
   end.
317

    
318
   put stream frpt unformatted space(3) '</text>' skip.
319
   input stream fnames close.
320
end.
321

    
322
put stream frpt unformatted "</text-list>" skip.
323

    
324
output stream frpt close.
325
input stream flines close.
326

    
327
message "The metrics were captured in file:" fxmlname.