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
321 stars 93 forks source link

Code not compiling under latest version #223

Closed birbilis closed 1 year ago

birbilis commented 2 years ago

After upgrading to latest version, this code breaks:

  var bitmap := Glyph.MultiResBitmap[0] as TSVGIconFixedBitmapItem;
  bitmap.SVG.LoadFromStream(Stream);

[dcc32 Error] READCOM.Views.VectorImageStoryItem.pas(103): E2362 Cannot access protected symbol TFmxImageSVG.LoadFromStream

can try re-building http://github.com/zoomicon/READCOM_App to see this

the reason is the LoadFromStream method is protected and abstract now (which is strange since one may not just want to load from a file or from text)

I guess I can use a memory stream or something, but would be nice if I could directly use LoadFromStream as before

birbilis commented 2 years ago

btw, I may remove that code anyway and use direct drawing like in SVGViewer demo's FrameViewer.pas, since the above approach seems to cause pixelization upon zooming into the container https://youtu.be/0vXp5jUf8cU?t=710

birbilis commented 2 years ago

ahem, tried to use FrameViewer.pas code, but seems one can't adapt it to FMX from VCL, since it uses ISVG.PaintTo method that expects a Handle. How would one go to port that to FMX and draw directly into an FMX PaintBox's Canvas?

image

carloBarazzetta commented 2 years ago

The FMX implementation does not use interfaces but according to the compilation directive:

birbilis commented 2 years ago

Problem is how can I stretch an image with FMX TSVGIconImage? I can't use TGlyph and ImageList in my case. Note the last parameter of PaintTo above, it was for stretching if I remember well

birbilis commented 2 years ago

to answer my own question, since TSVGIconImage descends from TImage (hadn't noticed) one can just do MySVGImg.WrapMode := TImageWrapMode.Stretch;

birbilis commented 2 years ago

So one thing that remains problematic in my case is this pixelization upon zooming in the container (I do zoom via ScaleLayout). Seems TSVGIconImage draws pixelized graphics when I zoom in, probably it treats FMX graphics as if they were integers (instead of singles). I'd expect it to always create a background buffer (and update it on resize) that is (widthscaleX, heightscaleY) sized. It also has some zoom parameter that I don't really understand what is supposed to do, it causes even more pixelization (plus that zoom param is integer and not single, so can't set it to 1/n in case it would do oversampling)

image

carloBarazzetta commented 2 years ago

I am not an FMX expert and I have implemented the BitmapZoom property (10 to 100%) to "reduce" the size of the image inside the container, when WrapMode is Original, Place or Tile... It is the same property used for the VCL version of the same component. If you use BitmapZoom instead of Scale probably the image is not pixelated ... Try and give me some feedback ...

birbilis commented 2 years ago

Not sure I understand how that BitmapZoom works, last time I tried BitmapZoom (is an integer, not a single number so can't use 0,5 for example) with a value>1 it resulted in even more pixelation.

From my perspective, the SVG is an infinite resolution image source. Since you inherit TImage I think you should be able to make it behave similarly to how it does when one loads a high resolution image and draw it in a smaller area (note I treat SVG as infinite res image), by generating the buffer not based on boundsrect, but on absoluterect (aka how big something shows on the screen - https://docwiki.embarcadero.com/Libraries/Sydney/en/FMX.Controls.TControl.AbsoluteRect).

Question is though how do you get notified that absolutrect changed. Now I see in your code you redraw the buffer when the bounds change (being in a scaled parent doesn't change children bounds) and in some other cases. Probably in all cases where the backbuffer is redrawn it should use AbsoluteRect. Might even save some memory and avoid scaling down artefacts when user has zoomed out (in which case AbsoluteRect is smaller than Local BoundsRect). Note in my case I have AbsoluteRect>>BoundsRect (have a zoom in by using a ScaledLayout container)

Since you also seem to use MultiScale bitmaps maybe you don't even need to listen for bounds changes and FMX will ask you for the proper resolution drawing (if you could tell it to do in small steps even better, not sure if it's configurable). But haven't read much on how MultiScale bitmaps work (e.g. don't how Scale/ScaleRange of bitmaps work that are mentioned here https://docwiki.embarcadero.com/Libraries/Sydney/en/FMX.MultiResBitmap.TCustomBitmapItem.Scale), so not sure

birbilis commented 2 years ago

At first I guessed you might need a TCustomMultiResBitmap descendent that spits out bitmaps of any resolution.

However, it seems that FMX asks what bitmap Scales are provided to judge which bitmap to use and then you have to pass it the Scale it asks for. Even if you used RegisterScale (and just provide one based on the AbsoluteRect) on the fly when it asked for a list of scales, not sure how often it will ask you for the list of scales. Aka if it will ask for that at each repaint due to parent control rescaling (FMX controls have Scale property and there is also ScaledLayout that scales its children [multiplying the scaling effect their own - or their children/grandchildren etc. - Scale setting may already have])

UPDATE: now that I see it again, I see a RegisterScaleName (https://docwiki.embarcadero.com/Libraries/Sydney/en/FMX.MultiResBitmap.RegisterScaleName) that probably is more design-oriented (I hope). Instead TCustomMultiResBitmap has ItemByScale and ScaleArray at https://docwiki.embarcadero.com/Libraries/Sydney/en/FMX.MultiResBitmap.TCustomMultiResBitmap_Methods so if one made the ScaleArray property only return one scale value based on the AbsoluteScale (https://docwiki.embarcadero.com/Libraries/Sydney/en/FMX.Controls.TControl.AbsoluteScale) and the ItemByScale to return the appropriate bitmap (could have it then cached till other AbsoluteScale is detected at ScaleArray getter upon which it would be dropped), then it might work to have infinite resolution images

birbilis commented 2 years ago

btw, Skia4Delphi also has some image drawing control, not sure if that descends from TImage or not. If it does, have they done this infinite resolution thing I'm taking about maybe already in their code?

carloBarazzetta commented 2 years ago

Can I close this issue?