EtheaDev / SVGIconImageList

Three engines to render SVG (Delphi Image32, Skia4Delphi, Direct2D wrapper) and four components to simplify use of SVG images (resize, fixedcolor, grayscale...)
Apache License 2.0
327 stars 96 forks source link

TSVGIconImageCollection with Image32 #188

Closed shineworld closed 3 years ago

shineworld commented 3 years ago

Hi all, I'm moving to the new SVGIconImageList which uses Image32 how default render.

I have a problem with TSVGIconImageCollection that I use for SVG icons repository in custom buttons. In the older version the code:

          IW := FImageCollection.SVGIconItems.Items[I].SVG.Width;
          IH := FImageCollection.SVGIconItems.Items[I].SVG.Height;

return the right SVG container width and height but in new version, which uses Image32, I get always Width & Height = 0.

Attached the project to test it. aggbutton.zip

pyscripter commented 3 years ago

Other backends set the width and height from the viewport if they are not explicitly specified (and the reverse).

carloBarazzetta commented 3 years ago

Try those two changes and give me if you obtain the same result using TSVG: 1) add this method into Image32SVGFactory.pas

procedure TImage32SVG.UpdateSizeInfo;
begin
  FWidth := fSvgReader.GetViewbox(0,0).Width;
  FHeight := fSvgReader.GetViewbox(0,0).Height;
end;

But I'm not 100% sure that the correct way to obtain width and height from fSvgReader is this!

then call it into:

procedure TImage32SVG.LoadFromSource;
begin
  if FSource <> '' then
  begin
    if not fSvgReader.LoadFromString(FSource) then
      raise Exception.Create('Error parsing SVG');
    UpdateSizeInfo; <=== HERE
  end;
end;

and into: procedure TImage32SVG.LoadFromStream(Stream: TStream); Var OldPos : Int64; begin // read and save the Source OldPos := Stream.Position; SourceFromStream(Stream); // Restore Position Stream.Position := OldPos; // Now create the SVG fSvgReader.LoadFromStream(Stream); UpdateSizeInfo; <=== HERE end;

AngusJohnson commented 3 years ago
procedure TImage32SVG.UpdateSizeInfo(defaultWidth, defaultHeight: integer);
var
  vbox: TRectWH;
begin
  //nb: default widths should be the target image's dimensions
  //since these values will be used for SVG images that simply 
  //specify their widths and heights as percentages
  vbox := fSvgReader.GetViewbox(defaultWidth, defaultHeight);
  FWidth := vbox.Width;
  FHeight := vbox.Height;
end;

Note: I'm just about to release Image32 version 3 which has had a major redesign of the file structure. The zip package will include an upgrade utility to streamline upgrading existing code that utilises the Image32 library.

carloBarazzetta commented 3 years ago
procedure TImage32SVG.UpdateSizeInfo(defaultWidth, defaultHeight: integer);
var
  vbox: TRectWH;
begin
  //nb: default widths should be the target image's dimensions
  //since these values will be used for SVG images that simply 
  //specify their widths and heights as percentages
  vbox := fSvgReader.GetViewbox(defaultWidth, defaultHeight);
  FWidth := vbox.Width;
  FHeight := vbox.Height;
end;

Note: I'm just about to release Image32 version 3 which has had a major redesign of the file structure. The zip package will include an upgrade utility to streamline upgrading existing code that utilises the Image32 library.

I don't know the size of the target image, because I'm calling UpdateSizeInfo into LoadFromStream or LoadFromSource but I need to update FWidth and FHeight of TImage32SVG using the size specified into ViewBox or by Width and Height.

Look at this similar code into D2DSVGFactory:

    if not Succeeded(DeviceContext5.CreateSvgDocument(XStream, D2D1SizeF(100, 100), // some initial values
    fSvgDoc)) then
      RaiseLastOSError;
    fsvgDoc.GetRoot(Root);
    if Root.IsAttributeSpecified('width', nil) then
      Root.GetAttributeValue('width', D2D1_SVG_ATTRIBUTE_POD_TYPE_FLOAT, @fWidth, SizeOf(fWidth));
    if Root.IsAttributeSpecified('height', nil) then
      Root.GetAttributeValue('height', D2D1_SVG_ATTRIBUTE_POD_TYPE_FLOAT, @fHeight, SizeOf(fHeight));
    // If width or height are missing try to get them from the Viewbox
    if ((fWidth = 0) or (fHeight = 0)) and (Root.GetAttributeValue('viewBox', D2D1_SVG_ATTRIBUTE_POD_TYPE_VIEWBOX, @ViewBox, SizeOf(ViewBox)) = S_OK) then
    begin
      if fWidth = 0 then
        fWidth := ViewBox.width;
      if fHeight = 0 then
        fHeight := ViewBox.height;
    end;

In D2DSVGFactory a 100 x 100 default size is used by @pyscripter: can we do the same in TImage32SVG ?

AngusJohnson commented 3 years ago

In D2DSVGFactory a 100 x 100 default size is used by @pyscripter: can we do the same in TImage32SVG ?

Sure, you can pretty much use any default values you want (ie for those images without a specific size).