mirror of
https://gitlab.com/freepascal.org/lazarus/lazarus.git
synced 2025-08-17 04:29:28 +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;
|
FLayerStylesKeys, FLayerStylesValues: TFPList; // of TStringList;
|
||||||
function ReadSVGColor(AValue: string): TFPColor;
|
function ReadSVGColor(AValue: string): TFPColor;
|
||||||
function ReadSVGStyle(AValue: string; ADestEntity: TvEntityWithPen; AUseFillAsPen: Boolean = False): TvSetPenBrushAndFontElements;
|
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 ReadSVGPenStyleWithKeyAndValue(AKey, AValue: string; ADestEntity: TvEntityWithPen): TvSetPenBrushAndFontElements;
|
||||||
function ReadSVGBrushStyleWithKeyAndValue(AKey, AValue: string; ADestEntity: TvEntityWithPenAndBrush): TvSetPenBrushAndFontElements;
|
function ReadSVGBrushStyleWithKeyAndValue(AKey, AValue: string; ADestEntity: TvEntityWithPenAndBrush): TvSetPenBrushAndFontElements;
|
||||||
function ReadSVGFontStyleWithKeyAndValue(AKey, AValue: string; ADestEntity: TvEntityWithPenBrushAndFont): TvSetPenBrushAndFontElements;
|
function ReadSVGFontStyleWithKeyAndValue(AKey, AValue: string; ADestEntity: TvEntityWithPenBrushAndFont): TvSetPenBrushAndFontElements;
|
||||||
@ -78,6 +79,7 @@ type
|
|||||||
procedure ReadLineFromNode(ANode: TDOMNode; AData: TvVectorialPage; ADoc: TvVectorialDocument);
|
procedure ReadLineFromNode(ANode: TDOMNode; AData: TvVectorialPage; ADoc: TvVectorialDocument);
|
||||||
procedure ReadPathFromNode(ANode: TDOMNode; AData: TvVectorialPage; ADoc: TvVectorialDocument);
|
procedure ReadPathFromNode(ANode: TDOMNode; AData: TvVectorialPage; ADoc: TvVectorialDocument);
|
||||||
procedure ReadPathFromString(AStr: string; 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 ReadPointsFromString(AStr: string; AData: TvVectorialPage; ADoc: TvVectorialDocument; AClosePath: Boolean);
|
||||||
procedure ReadPolyFromNode(ANode: TDOMNode; AData: TvVectorialPage; ADoc: TvVectorialDocument);
|
procedure ReadPolyFromNode(ANode: TDOMNode; AData: TvVectorialPage; ADoc: TvVectorialDocument);
|
||||||
procedure ReadRectFromNode(ANode: TDOMNode; AData: TvVectorialPage; ADoc: TvVectorialDocument);
|
procedure ReadRectFromNode(ANode: TDOMNode; AData: TvVectorialPage; ADoc: TvVectorialDocument);
|
||||||
@ -95,6 +97,7 @@ type
|
|||||||
constructor Create; override;
|
constructor Create; override;
|
||||||
Destructor Destroy; override;
|
Destructor Destroy; override;
|
||||||
procedure ReadFromStream(AStream: TStream; AData: TvVectorialDocument); override;
|
procedure ReadFromStream(AStream: TStream; AData: TvVectorialDocument); override;
|
||||||
|
procedure ReadFromXML(Doc: TXMLDocument; AData: TvVectorialDocument);
|
||||||
end;
|
end;
|
||||||
|
|
||||||
implementation
|
implementation
|
||||||
@ -698,6 +701,36 @@ begin
|
|||||||
end;
|
end;
|
||||||
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,
|
function TvSVGVectorialReader.ReadSVGPenStyleWithKeyAndValue(AKey,
|
||||||
AValue: string; ADestEntity: TvEntityWithPen): TvSetPenBrushAndFontElements;
|
AValue: string; ADestEntity: TvEntityWithPen): TvSetPenBrushAndFontElements;
|
||||||
var
|
var
|
||||||
@ -982,7 +1015,9 @@ begin
|
|||||||
lNodeName := ANode.Attributes.Item[i].NodeName;
|
lNodeName := ANode.Attributes.Item[i].NodeName;
|
||||||
if lNodeName = 'style' then
|
if lNodeName = 'style' then
|
||||||
begin
|
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)
|
lLayer.SetPenBrushAndFontElements += ReadSVGStyle(ANode.Attributes.Item[i].NodeValue, lLayer)
|
||||||
{$endif}
|
{$endif}
|
||||||
end
|
end
|
||||||
@ -1116,6 +1151,7 @@ var
|
|||||||
CurX, CurY: Double;
|
CurX, CurY: Double;
|
||||||
lCurTokenType, lLastCommandToken: TSVGTokenType;
|
lCurTokenType, lLastCommandToken: TSVGTokenType;
|
||||||
lDebugStr: String;
|
lDebugStr: String;
|
||||||
|
lTmpTokenType: TSVGTokenType;
|
||||||
begin
|
begin
|
||||||
FSVGPathTokenizer.Tokens.Clear;
|
FSVGPathTokenizer.Tokens.Clear;
|
||||||
FSVGPathTokenizer.TokenizePathString(AStr);
|
FSVGPathTokenizer.TokenizePathString(AStr);
|
||||||
@ -1128,7 +1164,31 @@ begin
|
|||||||
while i < FSVGPathTokenizer.Tokens.Count do
|
while i < FSVGPathTokenizer.Tokens.Count do
|
||||||
begin
|
begin
|
||||||
lCurTokenType := FSVGPathTokenizer.Tokens.Items[i].TokenType;
|
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
|
// Moves
|
||||||
// --------------
|
// --------------
|
||||||
@ -1154,21 +1214,6 @@ begin
|
|||||||
Inc(i, 3);
|
Inc(i, 3);
|
||||||
end
|
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
|
// Close Path
|
||||||
// --------------
|
// --------------
|
||||||
else if lCurTokenType = sttClosePath then
|
else if lCurTokenType = sttClosePath then
|
||||||
@ -1357,7 +1402,6 @@ begin
|
|||||||
Inc(i);
|
Inc(i);
|
||||||
end;
|
end;
|
||||||
end;
|
end;
|
||||||
end;
|
|
||||||
|
|
||||||
procedure TvSVGVectorialReader.ReadPointsFromString(AStr: string;
|
procedure TvSVGVectorialReader.ReadPointsFromString(AStr: string;
|
||||||
AData: TvVectorialPage; ADoc: TvVectorialDocument; AClosePath: Boolean);
|
AData: TvVectorialPage; ADoc: TvVectorialDocument; AClosePath: Boolean);
|
||||||
@ -1649,18 +1693,64 @@ procedure TvSVGVectorialReader.ReadFromStream(AStream: TStream;
|
|||||||
AData: TvVectorialDocument);
|
AData: TvVectorialDocument);
|
||||||
var
|
var
|
||||||
Doc: TXMLDocument;
|
Doc: TXMLDocument;
|
||||||
lCurNode: TDOMNode;
|
|
||||||
lPage: TvVectorialPage;
|
|
||||||
begin
|
begin
|
||||||
try
|
try
|
||||||
// Read in xml file from the stream
|
// Read in xml file from the stream
|
||||||
ReadXMLFile(Doc, AStream);
|
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
|
// Read the properties of the <svg> tag
|
||||||
|
// ----------------
|
||||||
AData.Width := StringWithUnitToFloat(Doc.DocumentElement.GetAttribute('width'));
|
AData.Width := StringWithUnitToFloat(Doc.DocumentElement.GetAttribute('width'));
|
||||||
AData.Height := StringWithUnitToFloat(Doc.DocumentElement.GetAttribute('height'));
|
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
|
// Now process the elements
|
||||||
|
// ----------------
|
||||||
lCurNode := Doc.DocumentElement.FirstChild;
|
lCurNode := Doc.DocumentElement.FirstChild;
|
||||||
lPage := AData.AddPage();
|
lPage := AData.AddPage();
|
||||||
lPage.Width := AData.Width;
|
lPage.Width := AData.Width;
|
||||||
@ -1670,10 +1760,17 @@ begin
|
|||||||
ReadEntityFromNode(lCurNode, lPage, AData);
|
ReadEntityFromNode(lCurNode, lPage, AData);
|
||||||
lCurNode := lCurNode.NextSibling;
|
lCurNode := lCurNode.NextSibling;
|
||||||
end;
|
end;
|
||||||
finally
|
|
||||||
// finally, free the document
|
// ----------------
|
||||||
Doc.Free;
|
// Remove the memory of the styles
|
||||||
end;
|
// ----------------
|
||||||
|
{$ifdef SVG_MERGE_LAYER_STYLES}
|
||||||
|
// Now remove the style from this layer
|
||||||
|
FLayerStylesKeys.Remove(lLayerStyleKeys);
|
||||||
|
lLayerStyleKeys.Free;
|
||||||
|
FLayerStylesValues.Remove(lLayerStyleValues);
|
||||||
|
lLayerStyleValues.Free;
|
||||||
|
{$endif}
|
||||||
end;
|
end;
|
||||||
|
|
||||||
initialization
|
initialization
|
||||||
|
Loading…
Reference in New Issue
Block a user