source: trunk/Packages/bgrabitmap/bgraunits.pas

Last change on this file was 2, checked in by chronos, 5 years ago
File size: 9.0 KB
Line 
1unit BGRAUnits;
2
3{$mode objfpc}{$H+}
4
5interface
6
7uses
8 Classes, SysUtils, BGRABitmapTypes;
9
10type
11 TCSSUnit = (cuCustom, cuPixel,
12 cuCentimeter, cuMillimeter,
13 cuInch, cuPica, cuPoint,
14 cuFontEmHeight, cuFontXHeight, cuPercent);
15 TFloatWithCSSUnit = record
16 value: single;
17 CSSUnit: TCSSUnit;
18 end;
19
20function FloatWithCSSUnit(AValue: single; AUnit: TCSSUnit): TFloatWithCSSUnit;
21
22const
23 CSSUnitShortName: array[TCSSUnit] of string =
24 ('','px',
25 'cm','mm',
26 'in','pc','pt',
27 'em','ex','%');
28
29type
30 { TCSSUnitConverter }
31
32 TCSSUnitConverter = class
33 protected
34 function GetDefaultUnitHeight: TFloatWithCSSUnit; virtual;
35 function GetDefaultUnitWidth: TFloatWithCSSUnit; virtual;
36 function GetDpiScaleTransform: string;
37 function GetDpiX: single; virtual;
38 function GetDpiY: single; virtual;
39 function GetDPIScaled: boolean; virtual;
40 function GetDpiScaleX: single; virtual;
41 function GetDpiScaleY: single; virtual;
42 function GetFontEmHeight: TFloatWithCSSUnit; virtual;
43 function GetFontXHeight: TFloatWithCSSUnit; virtual;
44 property FontEmHeight: TFloatWithCSSUnit read GetFontEmHeight;
45 property FontXHeight: TFloatWithCSSUnit read GetFontXHeight;
46 property DefaultUnitWidth: TFloatWithCSSUnit read GetDefaultUnitWidth;
47 property DefaultUnitHeight: TFloatWithCSSUnit read GetDefaultUnitHeight;
48 public
49 function Convert(xy: single; sourceUnit, destUnit: TCSSUnit; dpi: single; containerSize: single = 0): single;
50 function ConvertWidth(x: single; sourceUnit, destUnit: TCSSUnit; containerWidth: single = 0): single; overload;
51 function ConvertHeight(y: single; sourceUnit, destUnit: TCSSUnit; containerHeight: single = 0): single; overload;
52 function ConvertWidth(AValue: TFloatWithCSSUnit; destUnit: TCSSUnit; containerWidth: single = 0): TFloatWithCSSUnit; overload;
53 function ConvertHeight(AValue: TFloatWithCSSUnit; destUnit: TCSSUnit; containerHeight: single = 0): TFloatWithCSSUnit; overload;
54 function ConvertCoord(pt: TPointF; sourceUnit, destUnit: TCSSUnit; containerWidth: single = 0; containerHeight: single = 0): TPointF; virtual;
55 class function parseValue(AValue: string; ADefault: TFloatWithCSSUnit): TFloatWithCSSUnit; overload;
56 class function parseValue(AValue: string; ADefault: single): single; overload;
57 class function formatValue(AValue: TFloatWithCSSUnit; APrecision: integer = 7): string; overload;
58 class function formatValue(AValue: single; APrecision: integer = 7): string; overload;
59 property DpiX: single read GetDpiX;
60 property DpiY: single read GetDpiY;
61 property DpiScaled: boolean read GetDPIScaled;
62 property DpiScaleX: single read GetDpiScaleX;
63 property DpiScaleY: single read GetDpiScaleY;
64 property DpiScaleTransform: string read GetDpiScaleTransform;
65 end;
66
67implementation
68
69var
70 formats: TFormatSettings;
71
72const InchFactor: array[TCSSUnit] of integer =
73 (9600, 9600,
74 254, 2540,
75 100, 600, 7200,
76 0, 0, 0);
77
78function FloatWithCSSUnit(AValue: single; AUnit: TCSSUnit): TFloatWithCSSUnit;
79begin
80 result.value:= AValue;
81 result.CSSUnit:= AUnit;
82end;
83
84{ TCSSUnitConverter }
85
86function TCSSUnitConverter.GetDpiScaleX: single;
87begin
88 result := 1;
89end;
90
91function TCSSUnitConverter.GetDpiScaleY: single;
92begin
93 result := 1;
94end;
95
96function TCSSUnitConverter.GetFontEmHeight: TFloatWithCSSUnit;
97begin
98 result := FloatWithCSSUnit(0,cuCustom);
99end;
100
101function TCSSUnitConverter.GetFontXHeight: TFloatWithCSSUnit;
102begin
103 result := FloatWithCSSUnit(0,cuCustom);
104end;
105
106function TCSSUnitConverter.GetDPIScaled: boolean;
107begin
108 result := false;
109end;
110
111function TCSSUnitConverter.GetDpiScaleTransform: string;
112begin
113 result := 'scale('+formatValue(DpiScaleX)+','+
114 formatValue(DpiScaleY)+')';
115end;
116
117function TCSSUnitConverter.GetDefaultUnitHeight: TFloatWithCSSUnit;
118begin
119 result := FloatWithCSSUnit(1,cuPixel);
120end;
121
122function TCSSUnitConverter.GetDefaultUnitWidth: TFloatWithCSSUnit;
123begin
124 result := FloatWithCSSUnit(1,cuPixel);
125end;
126
127function TCSSUnitConverter.GetDpiX: single;
128begin
129 result := 96;
130end;
131
132function TCSSUnitConverter.GetDpiY: single;
133begin
134 result := 96;
135end;
136
137function TCSSUnitConverter.Convert(xy: single; sourceUnit, destUnit: TCSSUnit;
138 dpi: single; containerSize: single): single;
139var sourceFactor, destFactor: integer;
140begin
141 //fallback values for cuCustom as pixels
142 if sourceUnit = cuCustom then sourceUnit := cuPixel;
143 if destUnit = cuCustom then destUnit := cuPixel;
144 if (sourceUnit = destUnit) then
145 result := xy
146 else
147 if sourceUnit = cuPercent then
148 begin
149 result := xy/100*containerSize;
150 end else
151 if sourceUnit = cuFontEmHeight then
152 begin
153 with FontEmHeight do result := Convert(xy*value,CSSUnit, destUnit, dpi);
154 end else
155 if sourceUnit = cuFontXHeight then
156 begin
157 with FontXHeight do result := Convert(xy*value,CSSUnit, destUnit, dpi);
158 end else
159 if destUnit = cuFontEmHeight then
160 begin
161 with FontEmHeight do
162 if value = 0 then result := 0
163 else result := Convert(xy/value,sourceUnit, CSSUnit, dpi);
164 end else
165 if destUnit = cuFontEmHeight then
166 begin
167 with FontXHeight do
168 if value = 0 then result := 0
169 else result := Convert(xy/value,sourceUnit, CSSUnit, dpi);
170 end else
171 if sourceUnit = cuPixel then
172 begin
173 if dpi = 0 then result := 0
174 else result := xy*(InchFactor[sourceUnit]/(dpi*100));
175 end else
176 if destUnit = cuPixel then
177 begin
178 if dpi = 0 then result := 0
179 else result := xy*((dpi*100)/InchFactor[sourceUnit]);
180 end else
181 begin
182 sourceFactor := InchFactor[sourceUnit];
183 destFactor := InchFactor[destUnit];
184 if (sourceFactor = 0) or (destFactor = 0) then
185 result := 0
186 else
187 result := xy*(destFactor/sourceFactor);
188 end;
189end;
190
191function TCSSUnitConverter.ConvertWidth(x: single; sourceUnit,
192 destUnit: TCSSUnit; containerWidth: single): single;
193begin
194 if sourceUnit = destUnit then
195 result := x
196 else if sourceUnit = cuCustom then
197 with DefaultUnitWidth do
198 begin
199 result := x*ConvertWidth(value,CSSUnit, destUnit, containerWidth)
200 end
201 else if destUnit = cuCustom then
202 with ConvertWidth(DefaultUnitWidth,sourceUnit) do
203 begin
204 if value = 0 then
205 result := 0
206 else
207 result := x/value;
208 end else
209 result := Convert(x, sourceUnit, destUnit, DpiX, containerWidth);
210end;
211
212function TCSSUnitConverter.ConvertHeight(y: single; sourceUnit,
213 destUnit: TCSSUnit; containerHeight: single): single;
214begin
215 if sourceUnit = cuCustom then
216 with DefaultUnitHeight do
217 begin
218 result := y*ConvertHeight(value,CSSUnit, destUnit, containerHeight)
219 end
220 else if destUnit = cuCustom then
221 with ConvertHeight(DefaultUnitHeight,sourceUnit) do
222 begin
223 if value = 0 then
224 result := 0
225 else
226 result := y/value;
227 end else
228 result := Convert(y, sourceUnit, destUnit, DpiY, containerHeight);
229end;
230
231function TCSSUnitConverter.ConvertWidth(AValue: TFloatWithCSSUnit;
232 destUnit: TCSSUnit; containerWidth: single): TFloatWithCSSUnit;
233begin
234 result.CSSUnit := destUnit;
235 result.value:= ConvertWidth(AValue.value,AValue.CSSUnit,destUnit,containerWidth);
236end;
237
238function TCSSUnitConverter.ConvertHeight(AValue: TFloatWithCSSUnit;
239 destUnit: TCSSUnit; containerHeight: single): TFloatWithCSSUnit;
240begin
241 result.CSSUnit := destUnit;
242 result.value:= ConvertHeight(AValue.value,AValue.CSSUnit,destUnit,containerHeight);
243end;
244
245function TCSSUnitConverter.ConvertCoord(pt: TPointF; sourceUnit,
246 destUnit: TCSSUnit; containerWidth: single; containerHeight: single): TPointF;
247begin
248 result.x := ConvertWidth(pt.x, sourceUnit, destUnit, containerWidth);
249 result.y := ConvertHeight(pt.y, sourceUnit, destUnit, containerHeight);
250end;
251
252class function TCSSUnitConverter.parseValue(AValue: string;
253 ADefault: TFloatWithCSSUnit): TFloatWithCSSUnit;
254var cssUnit: TCSSUnit;
255 errPos: integer;
256begin
257 AValue := trim(AValue);
258 result.CSSUnit:= cuCustom;
259 for cssUnit := succ(cuCustom) to high(cssUnit) do
260 if (length(AValue)>=length(CSSUnitShortName[cssUnit])) and
261 (CompareText(copy(AValue,length(AValue)-length(CSSUnitShortName[cssUnit])+1,length(CSSUnitShortName[cssUnit])),
262 CSSUnitShortName[cssUnit])=0) then
263 begin
264 AValue := copy(AValue,1,length(AValue)-length(CSSUnitShortName[cssUnit]));
265 result.CSSUnit := cssUnit;
266 break;
267 end;
268 val(AValue,result.value,errPos);
269 if errPos <> 0 then
270 result := ADefault;
271end;
272
273class function TCSSUnitConverter.parseValue(AValue: string; ADefault: single): single;
274var
275 errPos: integer;
276begin
277 AValue := trim(AValue);
278 val(AValue,result,errPos);
279 if errPos <> 0 then
280 result := ADefault;
281end;
282
283class function TCSSUnitConverter.formatValue(AValue: TFloatWithCSSUnit; APrecision: integer = 7): string;
284begin
285 result := FloatToStrF(AValue.value,ffGeneral,APrecision,0,formats)+CSSUnitShortName[AValue.CSSUnit];
286end;
287
288class function TCSSUnitConverter.formatValue(AValue: single; APrecision: integer
289 ): string;
290begin
291 result := FloatToStrF(AValue,ffGeneral,APrecision,0,formats);
292end;
293
294initialization
295
296 formats := DefaultFormatSettings;
297 formats.DecimalSeparator := '.';
298
299end.
300
Note: See TracBrowser for help on using the repository browser.