mirror of
https://gitlab.com/freepascal.org/lazarus/lazarus.git
synced 2025-07-28 20:36:30 +02:00
fpvectorial: Improves a lot the SVG reader. Finishes the support for commands without a command token, adds support for reading the style of the <svg> tag. Radad test image now almost perfect.
git-svn-id: trunk@40852 -
This commit is contained in:
parent
47d1848397
commit
810f515e86
@ -65,6 +65,7 @@ type
|
||||
FLayerStylesKeys, FLayerStylesValues: TFPList; // of TStringList;
|
||||
function ReadSVGColor(AValue: string): TFPColor;
|
||||
function ReadSVGStyle(AValue: string; ADestEntity: TvEntityWithPen; AUseFillAsPen: Boolean = False): TvSetPenBrushAndFontElements;
|
||||
function ReadSVGStyleToStyleLists(AValue: string; AStyleKeys, AStyleValues: TStringList): TvSetPenBrushAndFontElements;
|
||||
function ReadSVGPenStyleWithKeyAndValue(AKey, AValue: string; ADestEntity: TvEntityWithPen): TvSetPenBrushAndFontElements;
|
||||
function ReadSVGBrushStyleWithKeyAndValue(AKey, AValue: string; ADestEntity: TvEntityWithPenAndBrush): TvSetPenBrushAndFontElements;
|
||||
function ReadSVGFontStyleWithKeyAndValue(AKey, AValue: string; ADestEntity: TvEntityWithPenBrushAndFont): TvSetPenBrushAndFontElements;
|
||||
@ -78,6 +79,7 @@ type
|
||||
procedure ReadLineFromNode(ANode: TDOMNode; AData: TvVectorialPage; ADoc: TvVectorialDocument);
|
||||
procedure ReadPathFromNode(ANode: TDOMNode; AData: TvVectorialPage; ADoc: TvVectorialDocument);
|
||||
procedure ReadPathFromString(AStr: string; AData: TvVectorialPage; ADoc: TvVectorialDocument);
|
||||
procedure ReadNextPathCommand(ACurTokenType: TSVGTokenType; var i: Integer; var CurX, CurY: Double; AData: TvVectorialPage; ADoc: TvVectorialDocument);
|
||||
procedure ReadPointsFromString(AStr: string; AData: TvVectorialPage; ADoc: TvVectorialDocument; AClosePath: Boolean);
|
||||
procedure ReadPolyFromNode(ANode: TDOMNode; AData: TvVectorialPage; ADoc: TvVectorialDocument);
|
||||
procedure ReadRectFromNode(ANode: TDOMNode; AData: TvVectorialPage; ADoc: TvVectorialDocument);
|
||||
@ -95,6 +97,7 @@ type
|
||||
constructor Create; override;
|
||||
Destructor Destroy; override;
|
||||
procedure ReadFromStream(AStream: TStream; AData: TvVectorialDocument); override;
|
||||
procedure ReadFromXML(Doc: TXMLDocument; AData: TvVectorialDocument);
|
||||
end;
|
||||
|
||||
implementation
|
||||
@ -698,6 +701,36 @@ begin
|
||||
end;
|
||||
end;
|
||||
|
||||
// style="fill:none;stroke:black;stroke-width:3"
|
||||
function TvSVGVectorialReader.ReadSVGStyleToStyleLists(AValue: string;
|
||||
AStyleKeys, AStyleValues: TStringList): TvSetPenBrushAndFontElements;
|
||||
var
|
||||
lStr, lStyleKeyStr, lStyleValueStr: String;
|
||||
lStrings: TStringList;
|
||||
i, lPosEqual: Integer;
|
||||
begin
|
||||
Result := [];
|
||||
if AValue = '' then Exit;
|
||||
|
||||
// Now split using ";" separator
|
||||
lStrings := TStringList.Create;
|
||||
try
|
||||
lStrings.Delimiter := ';';
|
||||
lStrings.DelimitedText := LowerCase(AValue);
|
||||
for i := 0 to lStrings.Count-1 do
|
||||
begin
|
||||
lStr := lStrings.Strings[i];
|
||||
lPosEqual := Pos(':', lStr);
|
||||
lStyleKeyStr := Copy(lStr, 0, lPosEqual-1);
|
||||
lStyleValueStr := Copy(lStr, lPosEqual+1, Length(lStr));
|
||||
AStyleKeys.Add(lStyleKeyStr);
|
||||
AStyleValues.Add(lStyleValueStr);
|
||||
end;
|
||||
finally
|
||||
lStrings.Free;
|
||||
end;
|
||||
end;
|
||||
|
||||
function TvSVGVectorialReader.ReadSVGPenStyleWithKeyAndValue(AKey,
|
||||
AValue: string; ADestEntity: TvEntityWithPen): TvSetPenBrushAndFontElements;
|
||||
var
|
||||
@ -982,7 +1015,9 @@ begin
|
||||
lNodeName := ANode.Attributes.Item[i].NodeName;
|
||||
if lNodeName = 'style' then
|
||||
begin
|
||||
{$ifndef SVG_MERGE_LAYER_STYLES}
|
||||
{$ifdef SVG_MERGE_LAYER_STYLES}
|
||||
ReadSVGStyleToStyleLists(ANode.Attributes.Item[i].NodeValue, lLayerStyleKeys, lLayerStyleValues);
|
||||
{$else}
|
||||
lLayer.SetPenBrushAndFontElements += ReadSVGStyle(ANode.Attributes.Item[i].NodeValue, lLayer)
|
||||
{$endif}
|
||||
end
|
||||
@ -1116,6 +1151,7 @@ var
|
||||
CurX, CurY: Double;
|
||||
lCurTokenType, lLastCommandToken: TSVGTokenType;
|
||||
lDebugStr: String;
|
||||
lTmpTokenType: TSVGTokenType;
|
||||
begin
|
||||
FSVGPathTokenizer.Tokens.Clear;
|
||||
FSVGPathTokenizer.TokenizePathString(AStr);
|
||||
@ -1128,7 +1164,31 @@ begin
|
||||
while i < FSVGPathTokenizer.Tokens.Count do
|
||||
begin
|
||||
lCurTokenType := FSVGPathTokenizer.Tokens.Items[i].TokenType;
|
||||
if not (lCurTokenType = sttFloatValue) then lLastCommandToken := lCurTokenType;
|
||||
if not (lCurTokenType = sttFloatValue) then
|
||||
begin
|
||||
lLastCommandToken := lCurTokenType;
|
||||
ReadNextPathCommand(lCurTokenType, i, CurX, CurY, AData, ADoc);
|
||||
end
|
||||
else
|
||||
begin
|
||||
lTmpTokenType := lLastCommandToken;
|
||||
if lLastCommandToken = sttMoveTo then lTmpTokenType := sttLineTo;
|
||||
if lLastCommandToken = sttRelativeMoveTo then lTmpTokenType := sttRelativeLineTo;
|
||||
Dec(i);// because there is command token
|
||||
ReadNextPathCommand(lTmpTokenType, i, CurX, CurY, AData, ADoc);
|
||||
end;
|
||||
end;
|
||||
end;
|
||||
|
||||
procedure TvSVGVectorialReader.ReadNextPathCommand(ACurTokenType: TSVGTokenType;
|
||||
var i: Integer; var CurX, CurY: Double; AData: TvVectorialPage;
|
||||
ADoc: TvVectorialDocument);
|
||||
var
|
||||
X, Y, X2, Y2, X3, Y3: Double;
|
||||
lCurTokenType: TSVGTokenType;
|
||||
lDebugStr: String;
|
||||
begin
|
||||
lCurTokenType := ACurTokenType;
|
||||
// --------------
|
||||
// Moves
|
||||
// --------------
|
||||
@ -1154,21 +1214,6 @@ begin
|
||||
Inc(i, 3);
|
||||
end
|
||||
// --------------
|
||||
// Lines which appear without a command token and after a MoveTo
|
||||
// --------------
|
||||
else if (lCurTokenType = sttFloatValue) and (lLastCommandToken in [sttMoveTo, sttRelativeMoveTo]) then
|
||||
begin
|
||||
X := FSVGPathTokenizer.Tokens.Items[i].Value;
|
||||
Y := FSVGPathTokenizer.Tokens.Items[i+1].Value;
|
||||
ConvertSVGCoordinatesToFPVCoordinates(AData, X, Y, X, Y);
|
||||
|
||||
CurX := X;
|
||||
CurY := Y;
|
||||
AData.AddLineToPath(CurX, CurY);
|
||||
|
||||
Inc(i, 2);
|
||||
end
|
||||
// --------------
|
||||
// Close Path
|
||||
// --------------
|
||||
else if lCurTokenType = sttClosePath then
|
||||
@ -1357,7 +1402,6 @@ begin
|
||||
Inc(i);
|
||||
end;
|
||||
end;
|
||||
end;
|
||||
|
||||
procedure TvSVGVectorialReader.ReadPointsFromString(AStr: string;
|
||||
AData: TvVectorialPage; ADoc: TvVectorialDocument; AClosePath: Boolean);
|
||||
@ -1649,18 +1693,64 @@ procedure TvSVGVectorialReader.ReadFromStream(AStream: TStream;
|
||||
AData: TvVectorialDocument);
|
||||
var
|
||||
Doc: TXMLDocument;
|
||||
lCurNode: TDOMNode;
|
||||
lPage: TvVectorialPage;
|
||||
begin
|
||||
try
|
||||
// Read in xml file from the stream
|
||||
ReadXMLFile(Doc, AStream);
|
||||
ReadFromXML(Doc, AData);
|
||||
finally
|
||||
// finally, free the document
|
||||
Doc.Free;
|
||||
end;
|
||||
end;
|
||||
|
||||
procedure TvSVGVectorialReader.ReadFromXML(Doc: TXMLDocument;
|
||||
AData: TvVectorialDocument);
|
||||
var
|
||||
lCurNode: TDOMNode;
|
||||
lPage: TvVectorialPage;
|
||||
{$ifdef SVG_MERGE_LAYER_STYLES}
|
||||
lLayerStyleKeys, lLayerStyleValues: TStringList;
|
||||
{$endif}
|
||||
lNodeName: DOMString;
|
||||
ANode: TDOMElement;
|
||||
i: Integer;
|
||||
begin
|
||||
// ----------------
|
||||
// Read the properties of the <svg> tag
|
||||
// ----------------
|
||||
AData.Width := StringWithUnitToFloat(Doc.DocumentElement.GetAttribute('width'));
|
||||
AData.Height := StringWithUnitToFloat(Doc.DocumentElement.GetAttribute('height'));
|
||||
{$ifdef SVG_MERGE_LAYER_STYLES}
|
||||
FLayerStylesKeys.Clear;
|
||||
FLayerStylesValues.Clear;
|
||||
lLayerStyleKeys := TStringList.Create;
|
||||
lLayerStyleValues := TStringList.Create;
|
||||
FLayerStylesKeys.Add(lLayerStyleKeys);
|
||||
FLayerStylesValues.Add(lLayerStyleValues);
|
||||
{$endif}
|
||||
ANode := Doc.DocumentElement;
|
||||
for i := 0 to ANode.Attributes.Length - 1 do
|
||||
begin
|
||||
lNodeName := ANode.Attributes.Item[i].NodeName;
|
||||
if lNodeName = 'style' then
|
||||
begin
|
||||
{$ifdef SVG_MERGE_LAYER_STYLES}
|
||||
ReadSVGStyleToStyleLists(ANode.Attributes.Item[i].NodeValue, lLayerStyleKeys, lLayerStyleValues);
|
||||
{$endif}
|
||||
end
|
||||
else if IsAttributeFromStyle(lNodeName) then
|
||||
begin
|
||||
{$ifdef SVG_MERGE_LAYER_STYLES}
|
||||
lLayerStyleKeys.Add(lNodeName);
|
||||
lLayerStyleValues.Add(UTF16ToUTF8(ANode.Attributes.Item[i].NodeValue));
|
||||
{$endif}
|
||||
end;
|
||||
end;
|
||||
|
||||
// ----------------
|
||||
// Now process the elements
|
||||
// ----------------
|
||||
lCurNode := Doc.DocumentElement.FirstChild;
|
||||
lPage := AData.AddPage();
|
||||
lPage.Width := AData.Width;
|
||||
@ -1670,10 +1760,17 @@ begin
|
||||
ReadEntityFromNode(lCurNode, lPage, AData);
|
||||
lCurNode := lCurNode.NextSibling;
|
||||
end;
|
||||
finally
|
||||
// finally, free the document
|
||||
Doc.Free;
|
||||
end;
|
||||
|
||||
// ----------------
|
||||
// Remove the memory of the styles
|
||||
// ----------------
|
||||
{$ifdef SVG_MERGE_LAYER_STYLES}
|
||||
// Now remove the style from this layer
|
||||
FLayerStylesKeys.Remove(lLayerStyleKeys);
|
||||
lLayerStyleKeys.Free;
|
||||
FLayerStylesValues.Remove(lLayerStyleValues);
|
||||
lLayerStyleValues.Free;
|
||||
{$endif}
|
||||
end;
|
||||
|
||||
initialization
|
||||
|
Loading…
Reference in New Issue
Block a user