This repository has been archived on 2024-02-26. You can view files and clone it. You cannot open issues or pull requests or push a commit.
Files
MyPresenter1.0/bgrabitmap/bgraunits.pas
2015-02-08 16:52:18 -08:00

286 lines
8.3 KiB
ObjectPascal

unit BGRAUnits;
{$mode objfpc}{$H+}
interface
uses
Classes, SysUtils, BGRABitmapTypes;
type
TCSSUnit = (cuCustom, cuPixel,
cuCentimeter, cuMillimeter,
cuInch, cuPica, cuPoint,
cuFontEmHeight, cuFontXHeight, cuPercent);
TFloatWithCSSUnit = record
value: single;
CSSUnit: TCSSUnit;
end;
function FloatWithCSSUnit(AValue: single; AUnit: TCSSUnit): TFloatWithCSSUnit;
const
CSSUnitShortName: array[TCSSUnit] of string =
('','px',
'cm','mm',
'in','pc','pt',
'em','ex','%');
type
{ TCSSUnitConverter }
TCSSUnitConverter = class
protected
function GetDefaultUnitHeight: TFloatWithCSSUnit; virtual;
function GetDefaultUnitWidth: TFloatWithCSSUnit; virtual;
function GetDpiScaleTransform: string;
function GetDpiX: single; virtual;
function GetDpiY: single; virtual;
function GetDPIScaled: boolean; virtual;
function GetDpiScaleX: single; virtual;
function GetDpiScaleY: single; virtual;
function GetFontEmHeight: TFloatWithCSSUnit; virtual;
function GetFontXHeight: TFloatWithCSSUnit; virtual;
property FontEmHeight: TFloatWithCSSUnit read GetFontEmHeight;
property FontXHeight: TFloatWithCSSUnit read GetFontXHeight;
property DefaultUnitWidth: TFloatWithCSSUnit read GetDefaultUnitWidth;
property DefaultUnitHeight: TFloatWithCSSUnit read GetDefaultUnitHeight;
public
function Convert(xy: single; sourceUnit, destUnit: TCSSUnit; dpi: single): single;
function ConvertWidth(x: single; sourceUnit, destUnit: TCSSUnit): single;
function ConvertHeight(y: single; sourceUnit, destUnit: TCSSUnit): single;
function ConvertWidth(AValue: TFloatWithCSSUnit; destUnit: TCSSUnit): TFloatWithCSSUnit;
function ConvertHeight(AValue: TFloatWithCSSUnit; destUnit: TCSSUnit): TFloatWithCSSUnit;
function ConvertCoord(pt: TPointF; sourceUnit, destUnit: TCSSUnit): TPointF; virtual;
class function parseValue(AValue: string; ADefault: TFloatWithCSSUnit): TFloatWithCSSUnit;
class function formatValue(AValue: TFloatWithCSSUnit; APrecision: integer = 7): string;
class function formatValue(AValue: single; APrecision: integer = 7): string;
property DpiX: single read GetDpiX;
property DpiY: single read GetDpiY;
property DpiScaled: boolean read GetDPIScaled;
property DpiScaleX: single read GetDpiScaleX;
property DpiScaleY: single read GetDpiScaleY;
property DpiScaleTransform: string read GetDpiScaleTransform;
end;
implementation
var
formats: TFormatSettings;
const InchFactor: array[TCSSUnit] of integer =
(9600, 9600,
254, 2540,
100, 600, 7200,
0, 0, 0);
function FloatWithCSSUnit(AValue: single; AUnit: TCSSUnit): TFloatWithCSSUnit;
begin
result.value:= AValue;
result.CSSUnit:= AUnit;
end;
{ TCSSUnitConverter }
function TCSSUnitConverter.GetDpiScaleX: single;
begin
result := 1;
end;
function TCSSUnitConverter.GetDpiScaleY: single;
begin
result := 1;
end;
function TCSSUnitConverter.GetFontEmHeight: TFloatWithCSSUnit;
begin
result := FloatWithCSSUnit(0,cuCustom);
end;
function TCSSUnitConverter.GetFontXHeight: TFloatWithCSSUnit;
begin
result := FloatWithCSSUnit(0,cuCustom);
end;
function TCSSUnitConverter.GetDPIScaled: boolean;
begin
result := false;
end;
function TCSSUnitConverter.GetDpiScaleTransform: string;
begin
result := 'scale('+formatValue(DpiScaleX)+','+
formatValue(DpiScaleY)+')';
end;
function TCSSUnitConverter.GetDefaultUnitHeight: TFloatWithCSSUnit;
begin
result := FloatWithCSSUnit(1,cuPixel);
end;
function TCSSUnitConverter.GetDefaultUnitWidth: TFloatWithCSSUnit;
begin
result := FloatWithCSSUnit(1,cuPixel);
end;
function TCSSUnitConverter.GetDpiX: single;
begin
result := 96;
end;
function TCSSUnitConverter.GetDpiY: single;
begin
result := 96;
end;
function TCSSUnitConverter.Convert(xy: single; sourceUnit, destUnit: TCSSUnit;
dpi: single): single;
var sourceFactor, destFactor: integer;
begin
//fallback values for cuCustom as pixels
if sourceUnit = cuCustom then sourceUnit := cuPixel;
if destUnit = cuCustom then destUnit := cuPixel;
if (sourceUnit = destUnit) then
result := xy
else
if sourceUnit = cuFontEmHeight then
begin
with FontEmHeight do result := Convert(xy*value,CSSUnit, destUnit, dpi);
end else
if sourceUnit = cuFontXHeight then
begin
with FontXHeight do result := Convert(xy*value,CSSUnit, destUnit, dpi);
end else
if destUnit = cuFontEmHeight then
begin
with FontEmHeight do
if value = 0 then result := 0
else result := Convert(xy/value,sourceUnit, CSSUnit, dpi);
end else
if destUnit = cuFontEmHeight then
begin
with FontXHeight do
if value = 0 then result := 0
else result := Convert(xy/value,sourceUnit, CSSUnit, dpi);
end else
if sourceUnit = cuPixel then
begin
if dpi = 0 then result := 0
else result := xy*(InchFactor[sourceUnit]/(dpi*100));
end else
if destUnit = cuPixel then
begin
if dpi = 0 then result := 0
else result := xy*((dpi*100)/InchFactor[sourceUnit]);
end else
begin
sourceFactor := InchFactor[sourceUnit];
destFactor := InchFactor[destUnit];
if (sourceFactor = 0) or (destFactor = 0) then
result := 0
else
result := xy*(destFactor/sourceFactor);
end;
end;
function TCSSUnitConverter.ConvertWidth(x: single; sourceUnit,
destUnit: TCSSUnit): single;
begin
if sourceUnit = destUnit then
result := x
else if sourceUnit = cuCustom then
with DefaultUnitWidth do
begin
result := x*ConvertWidth(value,CSSUnit, destUnit)
end
else if destUnit = cuCustom then
with ConvertWidth(DefaultUnitWidth,sourceUnit) do
begin
if value = 0 then
result := 0
else
result := x/value;
end else
result := Convert(x, sourceUnit, destUnit, DpiX);
end;
function TCSSUnitConverter.ConvertHeight(y: single; sourceUnit,
destUnit: TCSSUnit): single;
begin
if sourceUnit = cuCustom then
with DefaultUnitHeight do
begin
result := y*ConvertHeight(value,CSSUnit, destUnit)
end
else if destUnit = cuCustom then
with ConvertHeight(DefaultUnitHeight,sourceUnit) do
begin
if value = 0 then
result := 0
else
result := y/value;
end else
result := Convert(y, sourceUnit, destUnit, DpiY);
end;
function TCSSUnitConverter.ConvertWidth(AValue: TFloatWithCSSUnit;
destUnit: TCSSUnit): TFloatWithCSSUnit;
begin
result.CSSUnit := destUnit;
result.value:= ConvertWidth(AValue.value,AValue.CSSUnit,destUnit);
end;
function TCSSUnitConverter.ConvertHeight(AValue: TFloatWithCSSUnit;
destUnit: TCSSUnit): TFloatWithCSSUnit;
begin
result.CSSUnit := destUnit;
result.value:= ConvertHeight(AValue.value,AValue.CSSUnit,destUnit);
end;
function TCSSUnitConverter.ConvertCoord(pt: TPointF; sourceUnit,
destUnit: TCSSUnit): TPointF;
begin
result.x := ConvertWidth(pt.x, sourceUnit, destUnit);
result.y := ConvertHeight(pt.y, sourceUnit, destUnit);
end;
class function TCSSUnitConverter.parseValue(AValue: string;
ADefault: TFloatWithCSSUnit): TFloatWithCSSUnit;
var cssUnit: TCSSUnit;
errPos: integer;
begin
AValue := trim(AValue);
result.CSSUnit:= cuCustom;
for cssUnit := succ(cuCustom) to high(cssUnit) do
if (length(AValue)>=length(CSSUnitShortName[cssUnit])) and
(CompareText(copy(AValue,length(AValue)-length(CSSUnitShortName[cssUnit])+1,length(CSSUnitShortName[cssUnit])),
CSSUnitShortName[cssUnit])=0) then
begin
AValue := copy(AValue,1,length(AValue)-length(CSSUnitShortName[cssUnit]));
result.CSSUnit := cssUnit;
break;
end;
val(AValue,result.value,errPos);
if errPos <> 0 then
result := ADefault;
end;
class function TCSSUnitConverter.formatValue(AValue: TFloatWithCSSUnit; APrecision: integer = 7): string;
begin
result := FloatToStrF(AValue.value,ffGeneral,APrecision,0,formats)+CSSUnitShortName[AValue.CSSUnit];
end;
class function TCSSUnitConverter.formatValue(AValue: single; APrecision: integer
): string;
begin
result := FloatToStrF(AValue,ffGeneral,APrecision,0,formats);
end;
initialization
formats := DefaultFormatSettings;
formats.DecimalSeparator := '.';
end.