diff --git a/components/fpspreadsheet/fpshtmlutils.pas b/components/fpspreadsheet/fpshtmlutils.pas
index 46defd664..48de0e342 100644
--- a/components/fpspreadsheet/fpshtmlutils.pas
+++ b/components/fpspreadsheet/fpshtmlutils.pas
@@ -40,6 +40,11 @@ procedure HTMLToRichText(AWorkbook: TsWorkbook; AFont: TsFont;
const AHTMLText: String; out APlainText: String;
out ARichTextParams: TsRichTextParams);
+procedure RichTextToHTML(AWorkbook: TsWorkbook; AFont: TsFont;
+ const APlainText: String; const ARichTextParams: TsRichTextParams;
+ out AHTMLText: String);
+
+
implementation
uses
@@ -891,7 +896,10 @@ begin
end;
-
+{@@ ----------------------------------------------------------------------------
+ Extracts rich-text parameters out of an html-formatted string and returns the
+ plain text
+-------------------------------------------------------------------------------}
procedure HTMLToRichText(AWorkbook: TsWorkbook; AFont: TsFont;
const AHTMLText: String; out APlainText: String;
out ARichTextParams: TsRichTextParams);
@@ -911,5 +919,212 @@ begin
end;
end;
+
+{==============================================================================}
+{ Rich-text-to-HTML conversion }
+{==============================================================================}
+
+type
+ TsChangeFlag = (cfFontName, cfFontSize, cfFontColor, cfFontPosition,
+ cfBold, cfItalic, cfUnderline, cfStrikeout);
+ TsChangeFlags = set of TsChangeFlag;
+
+ TsHTMLComposer = class
+ private
+ FPointSeparatorSettings: TFormatSettings;
+ FWorkbook: TsWorkbook;
+ FBaseFont: TsFont;
+ FPlainText: String;
+ FRichTextParams: TsRichTextParams;
+ FChangedParams: array of TsChangeFlags;
+ FFonts: array of TsFont;
+ FHTMLText: String;
+ function FindChangedParams(AStartIndex: Integer): Integer;
+ procedure GetFontsFromWorkbook;
+ function GetTextOfRichTextParam(AIndex: Integer): String;
+ procedure StoreChangedParams(AIndex: Integer);
+ protected
+ public
+ constructor Create(AWorkbook: TsWorkbook; AFont: TsFont);
+ function Exec(const APlainText: String; const ARichTextParams: TsRichTextParams): String;
+ end;
+
+constructor TsHTMLComposer.Create(AWorkbook: TsWorkbook; AFont: TsFont);
+begin
+ FPointSeparatorSettings := DefaultFormatSettings;
+ FPointSeparatorSettings.DecimalSeparator := '.';
+ FWorkbook := AWorkbook;
+ FBaseFont := AFont;
+end;
+
+function TsHTMLComposer.Exec(const APlainText: String;
+ const ARichTextParams: TsRichTextParams): String;
+var
+ i: Integer;
+begin
+ if Length(ARichTextParams) = 0 then
+ begin
+ Result := FPlainText;
+ exit;
+ end;
+
+ FRichTextParams := ARichTextParams;
+ FPlainText := APlainText;
+
+ GetFontsFromWorkbook;
+ SetLength(FChangedParams, Length(FRichTextParams));
+
+ if FRichTextParams[0].FirstIndex > 1 then
+ Result := GetTextOfRichTextParam(-1) else
+ Result := '';
+
+ for i:=0 to High(FRichTextParams) do
+ begin
+ // Remember what is changed in this step
+ StoreChangedParams(i);
+ // Find when these items were changed before
+ // j := FindChangedParams(i); --- not needed in the simple version
+ // For the changed items add an open tag
+ // NOTE: This is a simple version: every opened tag is closed afterwards!
+ // In a more advanced version, shared properties should be kept. This is
+ // what FChangedParams was introduced for!
+ if [cfFontName, cfFontSize, cfFontColor] * FChangedparams[i] <> [] then
+ begin
+ Result := Result + '';
+ if (cfItalic in FChangedParams[i]) then
+ Result := Result + '';
+ if (cfUnderline in FChangedParams[i]) then
+ Result := Result + '';
+ if (cfStrikeout in FChangedParams[i]) then
+ Result := Result + '';
+ if (cfFontPosition in FChangedParams[i]) then
+ begin
+ if FFonts[i].Position = fpSuperscript then Result := Result + '';
+ if FFonts[i].Position = fpSubscript then Result := Result + '';
+ end;
+ // Add the node text
+ Result := Result + GetTextOfRichTextParam(i);
+ // Add closing tags (reverse order as opening!)
+ if (cfFontPosition in FChangedParams[i]) then
+ begin
+ if FFonts[i].Position = fpSubscript then Result := Result + '';
+ if FFonts[i].Position = fpSuperscript then Result := Result + '';
+ end;
+ if (cfStrikeout in FChangedParams[i]) then
+ Result := Result + '';
+ if (cfUnderline in FChangedParams[i]) then
+ Result := Result + '';
+ if (cfItalic in FChangedParams[i]) then
+ Result := Result + '';
+ if (cfBold in FChangedParams[i]) then
+ Result := Result + '';
+ if [cfFontName, cfFontSize, cfFontColor] * FChangedParams[i] <> [] then
+ Result := Result + '= 0) and (cp * FChangedParams[Result] <> cp) do
+ dec(Result);
+end;
+
+procedure TsHTMLComposer.GetFontsFromWorkbook;
+var
+ i: Integer;
+begin
+ SetLength(FFonts, Length(FRichTextParams));
+ for i:=0 to High(FFonts) do
+ FFonts[i] := FWorkbook.GetFont(FRichTextParams[i].FontIndex);
+end;
+
+function TsHTMLComposer.GetTextOfRichTextParam(AIndex: Integer): String;
+var
+ p1, p2: Integer;
+begin
+ if AIndex = -1 then
+ Result := UTF8Copy(FPlainText, 1, FRichTextParams[0].FirstIndex-1)
+ else
+ if AIndex <= High(FRichTextParams) then
+ begin
+ p1 := FRichTextParams[AIndex].FirstIndex;
+ if AIndex < High(FRichTextparams) then
+ p2 := FRichTextParams[AIndex+1].FirstIndex else
+ p2 := UTF8Length(FPlainText) + 1;
+ Result := UTF8Copy(FPlaiNText, p1, p2-p1);
+ end else
+ Result := '';
+end;
+
+{ Entering the rich-text parameter region with the specified index. Detects
+ the font differences to the preceding section. }
+procedure TsHTMLComposer.StoreChangedParams(AIndex: Integer);
+const
+ EPS = 1e-3;
+var
+ fnt1, fnt2: TsFont;
+begin
+ // Font in previous section
+ if AIndex = 0 then
+ fnt1 := FBaseFont else
+ fnt1 := FFonts[AIndex-1];
+ // Font in current (new) section
+ fnt2 := FFonts[AIndex];
+ if not SameText(fnt1.FontName, fnt2.FontName) then
+ Include(FChangedParams[AIndex], cfFontName);
+ if not SameValue(fnt1.Size, fnt2.Size, EPS) then
+ Include(FChangedParams[Aindex], cfFontSize);
+ if fnt1.Color <> fnt2.Color then
+ Include(FChangedParams[AIndex], cfFontColor);
+ if fnt1.Position <> fnt2.Position then
+ Include(FChangedParams[AIndex], cfFontPosition);
+ if (fnt1.Style * [fssBold] <> fnt2.Style * [fssBold]) then
+ Include(FChangedParams[Aindex], cfBold);
+ if (fnt1.Style * [fssItalic] <> fnt2.Style * [fssItalic]) then
+ Include(FChangedParams[AIndex], cfItalic);
+ if (fnt1.Style * [fssUnderline] <> fnt2.style * [fssUnderline]) then
+ Include(FChangedParams[AIndex], cfUnderline);
+ if (fnt1.STyle * [fssStrikeout] <> fnt2.Style * [fssStrikeout]) then
+ Include(FChangedParams[AIndex], cfStrikeout);
+end;
+
+
+{@@ ----------------------------------------------------------------------------
+ Constructs a html-coded string from a plain text string and
+ rich-text parameters
+-------------------------------------------------------------------------------}
+procedure RichTextToHTML(AWorkbook: TsWorkbook; AFont: TsFont;
+ const APlainText: String; const ARichTextParams: TsRichTextParams;
+ out AHTMLText: String);
+var
+ composer: TsHTMLComposer;
+begin
+ if Length(ARichTextParams) = 0 then
+ AHTMLText := APlainText
+ else begin
+ composer := TsHTMLComposer.Create(AWorkbook, AFont);
+ try
+ AHTMLText := composer.Exec(APlainText, ARichTextParams);
+ finally
+ composer.Free;
+ end;
+ end;
+end;
+
end.
diff --git a/components/fpspreadsheet/fpsutils.pas b/components/fpspreadsheet/fpsutils.pas
index afd8a60a9..01f0c13f5 100644
--- a/components/fpspreadsheet/fpsutils.pas
+++ b/components/fpspreadsheet/fpsutils.pas
@@ -148,6 +148,7 @@ procedure InitPageLayout(out APageLayout: TsPageLayout);
procedure CopyCellValue(AFromCell, AToCell: PCell);
function HasFormula(ACell: PCell): Boolean;
function SameCellBorders(AFormat1, AFormat2: PsCellFormat): Boolean;
+function SameFont(AFont1, AFont2: TsFont): Boolean;
procedure AppendToStream(AStream: TStream; const AString: String); inline; overload;
procedure AppendToStream(AStream: TStream; const AString1, AString2: String); inline; overload;
@@ -1913,6 +1914,26 @@ begin
end;
end;
+{@@ ----------------------------------------------------------------------------
+ Checks whether two fonts are equal
+
+ @param AFormat1 Pointer to the first font to be compared
+ @param AFormat2 Pointer to the second font to be compared
+-------------------------------------------------------------------------------}
+function SameFont(AFont1, AFont2: TsFont): Boolean;
+const
+ EPS = 1E-3;
+begin
+ Result := (AFont1 <> nil) and (AFont2 <> nil) and
+ SameText(AFont1.FontName, AFont2.FontName) and
+ SameValue(AFont1.Size, AFont2.Size, EPS) and
+ (AFont1.Color = AFont2.Color) and
+ (AFont1.Style = AFont2.Style) and
+ (AFont1.Position = AFont2.Position);
+ if (AFont1 = nil) and (AFont2 = nil) then
+ Result := true;
+end;
+
{@@ ----------------------------------------------------------------------------
Appends a string to a stream