fpspreadsheet: Support reading of rotated images from ods files.

git-svn-id: https://svn.code.sf.net/p/lazarus-ccr/svn@9753 8e941d3f-bd1b-0410-a28a-d453659cc2b4
This commit is contained in:
wp_xxyyzz 2025-05-22 17:07:19 +00:00
parent 9ec7cea591
commit 9b1fe48c83
4 changed files with 114 additions and 58 deletions

View File

@ -5111,16 +5111,59 @@ procedure TsSpreadOpenDocReader.ReadShape(ANode: TDOMNode;
ARow: Cardinal = UNASSIGNED_ROW_COL_INDEX;
ACol: Cardinal = UNASSIGNED_ROW_COL_INDEX);
// Example for s: skewX (7.75940943781828E-017) rotate (1.0471975511966) translate (0.014cm -0.023cm)
procedure AnalyzeTransform(s: String; var SkewX, RotAngle, dX, dY: Double);
var
sa: TStringArray;
i: Integer;
valueStr: String;
relative: Boolean;
begin
SkewX := 0.0;
RotAngle := 0.0;
dX := 0.0;
dy := 0.0;
sa := s.Split(' ');
for i := 0 to High(sa) do
case sa[i] of
'skewX':
begin
valueStr := Copy(sa[i+1], 2, Length(sa[+1])-2);
SkewX := StrToFloatDef(valueStr, 0.0, FPointSeparatorSettings);
end;
'rotate':
begin
valueStr := Copy(sa[i+1], 2, Length(sa[+1])-2);
RotAngle := RadToDeg(StrToFloatDef(valueStr, 0.0, FPointSeparatorSettings));
end;
'translate':
begin
valueStr := Copy(sa[i+1], 2, Length(sa[+1])-2);
EvalLengthStr(valueStr, dX, relative);
valueStr := Copy(sa[i+2], 2, Length(sa[+2])-2);
EvalLengthStr(valueStr, dX, relative);
end;
end;
end;
procedure ReadDrawFrame(ANode: TDOMNode; AHLink: String);
var
r, c: Cardinal;
x, y, w, h: Double;
nodeName: String;
x: Double = 0.0;
y: Double = 0.0;
w: Double = 0.0;
h: Double = 0.0;
dx: Double = 0.0;
dy: Double = 0.0;
sx: Double = 1.0;
sy: Double = 1.0;
attr: String = '';
transfSkew: Double = 0.0;
transfAngle: Double = 0.0;
transfDX: Double = 0.0;
transfDY: Double = 0.0;
childNode: TDOMNode;
nodeName: String;
i, idx: Integer;
href: String;
img: PsImage;
@ -5131,10 +5174,14 @@ procedure TsSpreadOpenDocReader.ReadShape(ANode: TDOMNode;
{$ENDIF}
begin
nodeName := ANode.NodeName;
x := PtsToMM(HTMLLengthStrToPts(GetAttrValue(ANode, 'svg:x')));
y := PtsToMM(HTMLLengthStrToPts(GetAttrValue(ANode, 'svg:y')));
w := PtsToMM(HTMLLengthStrToPts(GetAttrValue(ANode, 'svg:width')));
h := PtsToMM(HTMLLengthStrToPts(GetAttrValue(ANode, 'svg:height')));
attr := GetAttrValue(ANode, 'svg:x');
if attr <> '' then x := PtsToMM(HTMLLengthStrToPts(attr));
attr := GetAttrValue(ANode, 'svg:y');
if attr <> '' then y := PtsToMM(HTMLLengthStrToPts(attr));
attr := GetAttrValue(ANode, 'svg:width');
if attr <> '' then h := PtsToMM(HTMLLengthStrToPts(attr));
attr := GetAttrValue(ANode, 'draw:transform');
if attr <> '' then AnalyzeTransform(attr, transfSkew, transfAngle, transfDX, transfDY);
childNode := ANode.FirstChild;
while Assigned(childNode) do
begin
@ -5185,10 +5232,10 @@ procedure TsSpreadOpenDocReader.ReadShape(ANode: TDOMNode;
dx := x;
end;
idx := WriteImage(r, c, idx, dx, dy, sx, sy);
if AHLink <> '' then begin
img := GetPointerToImage(idx);
img := GetPointerToImage(idx);
img^.RotationAngle := transfAngle;
if AHLink <> '' then
img^.HyperlinkTarget := AHLink;
end;
end;
end;
end;

View File

@ -267,43 +267,6 @@ begin
end;
end;
{ Extracts the length from an ods length string, e.g. "3.5cm" or "300%". In the
former case AValue become 35 (in millimeters), in the latter case AValue is
300 and Relative becomes true }
function EvalLengthStr(AText: String; out AValue: Double; out Relative: Boolean): Boolean;
var
i: Integer;
res: Integer;
units: String;
begin
Result := false;
if AText = '' then
exit;
units := '';
for i := Length(AText) downto 1 do
if AText[i] in ['%', 'm', 'c', 'p', 't', 'i', 'n'] then
begin
units := AText[i] + units;
Delete(AText, i, 1);
end;
Val(AText, AValue, res);
Result := (res = 0);
if res = 0 then
begin
Relative := false;
case units of
'%': Relative := true;
'mm': ;
'cm': AValue := AValue * 10;
'pt': AValue := PtsToMM(AValue);
'in': AValue := InToMM(AValue);
else Result := false;
end;
end;
end;
function ModifyColor(AColor: TsChartColor; AIntensity: double): TsChartColor;
begin
Result.Color := LumModOff(AColor.Color, AIntensity, 0.0);

View File

@ -62,6 +62,8 @@ function CreateTempStream(AWorkbook: TsBasicWorkbook;
AFileNameBase: String): TStream;
procedure DestroyTempStream(AStream: TStream);
function EvalLengthStr(AText: String; out AValue: Double; out Relative: Boolean): Boolean;
implementation
@ -231,6 +233,51 @@ begin
else
Result := '';
end;
{@@ ----------------------------------------------------------------------------
Extracts the length from an ods length string, e.g. "3.5cm" or "300%". In the
ormer case AValue become 35 (in millimeters), in the latter case AValue is
00 and Relative becomes true
@param AText Length string to be analyzed, e.g. "3.5cm"
@param AValue Numerical value, in cm, or as integer percentage
@param Relative If true the parameter AValue is a percentage, otherwise a length in millimeters
-------------------------------------------------------------------------------}
function EvalLengthStr(AText: String; out AValue: Double; out Relative: Boolean): Boolean;
var
i: Integer;
res: Integer;
units: String;
begin
Result := false;
if AText = '' then
exit;
units := '';
for i := Length(AText) downto 1 do
if AText[i] in ['%', 'm', 'c', 'p', 't', 'i', 'n'] then
begin
units := AText[i] + units;
Delete(AText, i, 1);
end;
Val(AText, AValue, res);
Result := (res = 0);
if res = 0 then
begin
Relative := false;
case units of
'%': Relative := true;
'mm': ;
'cm': AValue := AValue * 10;
'pt': AValue := PtsToMM(AValue);
'in': AValue := InToMM(AValue);
else Result := false;
end;
end;
end;
{------------------------------------------------------------------------------}
{ Unzipping }
{------------------------------------------------------------------------------}

View File

@ -342,20 +342,20 @@ type
TDateMode = (dm1900, dm1904); //DATEMODE values, 5.28
// Adjusts Excel float (date, date/time, time) with the file's base date to get a TDateTime
function ConvertExcelDateTimeToDateTime
(const AExcelDateNum: Double; ADateMode: TDateMode): TDateTime;
// Adjusts Excel float (date, date/time, time) with the file's base date to get a TDateTime
function ConvertExcelDateTimeToDateTime
(const AExcelDateNum: Double; ADateMode: TDateMode): TDateTime;
// Adjusts TDateTime with the file's base date to get
// an Excel float value representing a time/date/datetime
function ConvertDateTimeToExcelDateTime
(const ADateTime: TDateTime; ADateMode: TDateMode): Double;
// Adjusts TDateTime with the file's base date to get
// an Excel float value representing a time/date/datetime
function ConvertDateTimeToExcelDateTime
(const ADateTime: TDateTime; ADateMode: TDateMode): Double;
// Converts the error byte read from cells or formulas to fps error value
function ConvertFromExcelError(AValue: Byte): TsErrorValue;
// Converts the error byte read from cells or formulas to fps error value
function ConvertFromExcelError(AValue: Byte): TsErrorValue;
// Converts an fps error value to the byte code needed in xls files
function ConvertToExcelError(AValue: TsErrorValue): byte;
// Converts an fps error value to the byte code needed in xls files
function ConvertToExcelError(AValue: TsErrorValue): byte;
type
{ TsSheetData }
@ -5984,6 +5984,5 @@ begin
WriteXF(AStream, TsWorkbook(Workbook).GetPointerToCellFormat(i), 0);
end;
end.