SVG scaling [SOLVED]

New to Gambas? Post your questions here. No question is too silly or too simple.
Post Reply
JumpyVB
Posts: 75
Joined: Friday 11th September 2020 9:09am

SVG scaling [SOLVED]

Post by JumpyVB »

What is the best way to properly scale an svg graphic for use in Gambas IconView? Here's a hack I made to get the desired sharp result and and easier way which unfortunately yields a blurry result:
Public Sub Form_Open()
  Dim FilePath As String = "/usr/share/icons/Papirus/32x32/actions/home.svg"
  Dim TmpDescription As String = File.Name(FilePath)
  ' Method A = Sharp
  Dim FileAsData As String = FixSvgResolution(FilePath, "64", "64")
  Dim Pic_A As Picture = Picture.FromString(FileAsData)
  IconView1.Add(0, TmpDescription, Pic_A)
  ' Method B = Blurry
  Dim Pic_B As Picture = Picture.Load(FilePath)
  IconView1.Add(1, TmpDescription, Pic_B.Image.Stretch(64, 64).Picture)
End
Private Function FixSvgResolution(SvgPath As String, Optional DesiredWidth As String = "32px", Optional DesiredHeight As String = "32px") As String
  Dim FixedSvg As String
  Dim doc As New XmlDocument(SvgPath)
  Dim mainNode As XmlNode = doc.GetElementsByTagName("svg")[0] 'doc.All[0]
  Dim OrigWidth As String = ""
  Dim OrigHeight As String = ""
  Dim Header As String = Split(mainNode.ToString(), ">")[0]
  Dim Attributes As String[] = Split(Header, " ")
  Dim i As Integer
  For i = 0 To Attributes.Count - 1
    If Attributes[i] Like "*width=*" Then 
      OrigWidth = Split(Attributes[i], String.Chr(34))[1]
    Else If Attributes[i] Like "*height=*" Then 
      OrigHeight = Split(Attributes[i], String.Chr(34))[1]
    Endif
    If OrigWidth = "" Or OrigHeight = "" Then 
        'Keep looking
      Else 
        Exit 'For
    Endif
  Next
  If OrigWidth = "" Or OrigHeight = "" Then Error.Raise("File did not contain width and height!")
  mainNode.NewAttribute("width", DesiredWidth)
  mainNode.NewAttribute("height", DesiredHeight)
  ' mainNode.NewAttribute("viewBox", "0 0 16 16")
  mainNode.NewAttribute("viewBox", "0 0 " & OrigWidth & " " & OrigHeight)
  ' mainNode.NewAttribute("viewBox", "-0.2 -0.2 " & OrigWidth & ".4 " & OrigHeight & "16.4")
  FixedSvg = doc.ToString()
  Return FixedSvg
End
PS: DotNewAttribute does an update or replace to the existing attribute. But I could not find a proper way to read the xml attributes. So reading the original attribute values is another hack. I appreciate any advice in this regard aswell.
Last edited by JumpyVB on Wednesday 5th April 2023 4:42pm, edited 1 time in total.
User avatar
cogier
Site Admin
Posts: 1126
Joined: Wednesday 21st September 2016 2:22pm
Location: Guernsey, Channel Islands

Re: SVG scaling

Post by cogier »

What is the best way to properly scale an svg graphic for use in Gambas IconView?
Well, I have just spent about an hour and a half on this and came up with the following that uses a little less code. Note that line 24 is needed as for some reason a SVG image saved at 128,128 ends up at 160,160!

Public Sub Form_Open()

  Dim FilePath As String = "/usr/share/icons/Papirus/32x32/actions/home.svg"
  Dim Pic_A As Picture = Picture.Load(FilePath)
  Dim TmpDescription As String = File.Name(FilePath)

  ' Method A = Sharp
  IconView1.Add(0, TmpDescription, LoadSVG(FilePath, 256, 256))

  ' Method B = Blurry
  IconView1.Add(1, TmpDescription, Pic_A.Image.Stretch(256, 256).Picture)

End

Public Sub LoadSVG(sPath As String, iWidth As Integer, iHeight As Integer) As Picture

  Dim hSVG As SvgImage = SvgImage.Load(sPath)
  Dim pPic As Picture

  hSVG.Resize(iWidth, iHeight)
  If Exist("/tmp/SVG.svg") Then Kill "/tmp/SVG.svg"
  hSVG.Save("/tmp/SVG.svg")
  pPic = Picture["/tmp/SVG.svg"]
  pPic = pPic.Image.Resize(iWidth, iHeight).Picture 'Needed as the SVG file is bigger

  Return pPic

End


Image
JumpyVB
Posts: 75
Joined: Friday 11th September 2020 9:09am

Re: SVG scaling

Post by JumpyVB »

Thank you for your effort cogier. Makes me think I should take a peek at the source code of SvgImage.Resize. I will come back if I find something amazing.

It's a shame that using svgs in gambas is not a trivial task.
User avatar
BruceSteers
Posts: 1575
Joined: Thursday 23rd July 2020 5:20pm
Location: Isle of Wight
Contact:

Re: SVG scaling

Post by BruceSteers »

I guess with svg you can use resize and paint to make a Picture object.

Here's a function to create a Picture object from an svgimage using it's Resize and Paint methods


'' convert an svg image to a picture

Public Sub SvgToPic(sPath As String, W As Integer, H As Integer) As Picture
  
  Dim sv As SvgImage = SvgImage.Load(sPath)  ' load svg

  Dim p As Picture = New Picture(W, H, True)  ' make a Picture object (transparent bg)

  sv.Resize(W, H)  ' resize svg

  Paint.Begin(p)  ' paint svg to the picture
  sv.Paint(0, 0, W, H)
  Paint.End
  Return p
  
End



PS. svgimage according to wiki is not great because qt svg methods are buggy.
https://gambaswiki.org/wiki/comp/gb.qt4/svgimage
If at first you don't succeed , try doing something differently.
BruceS
JumpyVB
Posts: 75
Joined: Friday 11th September 2020 9:09am

Re: SVG scaling

Post by JumpyVB »

Thank you Bruce. It's elegant and it works.
Post Reply