How to scale and center SVGs

MisterAcousticMisterAcoustic ✭✭Member ✭✭

I have svg graphics that I am scaling to the size of the Buttons that contain them. I am maintaining the aspect ratio of the graphics (ignore the Stretch option).

I would like to also be able to center the graphics in the Button - for example, if the width of the button is larger than the height, the image is scaled to the height of the Button (and so is automatically centered in that dimension), but the image will need to be translated some distance to put it in the middle width-wise. And vice-versa, if the button height is greater than the width.

Here is my current code. I will ask my questions below.

            SKCanvas canvas = args.Surface.Canvas;
            canvas.Clear();
            canvas.ResetMatrix();

        ...

                    SKSvg svg = new SKSvg();
                    svg.Load(stream);

                    SKMatrix matrix;

                    float containerHeight = (float)this.Height;
                    float containerWidth = (float)this.Width;

                    float pictureHeight = (float)svg.Picture.CullRect.Height;
                    float pictureWidth = (float)svg.Picture.CullRect.Width;

                    float heightScale = containerHeight / pictureHeight;
                    float widthScale = containerWidth / pictureWidth;

                    // not sure why, but scale must be increased to properly size the image in the container
                    heightScale = (float)(heightScale * 1.5);
                    widthScale = (float)(widthScale * 1.5);

            if (ScaleType == ScaleType.Aspect)
                    {
                        float aspectScale = 0f;
                        if (containerHeight == containerWidth)      // I know this is not complete
                        {
                            aspectScale = widthScale;
                        }
                        else if (containerHeight > containerWidth)
                        {
                            aspectScale = widthScale;

                            if (Center)
                            {
                                float scaledPictureHeight = pictureHeight * aspectScale;
                                float heightChange = (containerHeight / 2) - (scaledPictureHeight / 2);
                                heightChange = Math.Abs(heightChange);

                                canvas.Translate(0, heightChange);
                            }
                        }
                        else
                        {
                            aspectScale = heightScale;

                            if (Center)
                            {
                                float scaledPictureWidth = pictureWidth * aspectScale;
                                float widthChange = (containerWidth / 2) - (scaledPictureWidth / 2);
                                widthChange = Math.Abs(widthChange);

                                canvas.Translate(widthChange, 0);
                            }
                        }

                        // create a scale matrix
                        matrix = SKMatrix.MakeScale(aspectScale, aspectScale);
                    }

                    // draw the picture with the matrix
                    canvas.DrawPicture(svg.Picture, ref matrix);

Results:
I tried to post a picture of the results, but apparently I'm too new here to do that. Basically, the images do not translate the proper amount for them to end up in the center of the button/container.

Questions:

1) Why in the devil do I have to multiply my scale factors by 1.5 in order to get the svg to fill the specified size?

2) The calculation to determine the correct offset for translation seems straightforward (e.g. float change = (containerDimension / 2) - (scaledPictureDimension / 2); ), but calculating that value and using it in canvas.Translate does not put the graphic in the middle of the button in the desired dimension. What is happening?

Thanks in advance for any help.

Best Answer

Answers

  • MisterAcousticMisterAcoustic ✭✭ Member ✭✭

    Hi AlexP - thank you so much for your article. In fact, I had seen it before, but I failed to realized that you had solved the centering issue as well. We worked out our own code for centering that is about 10 times as long as yours :).

    To answer the questions that I asked in the original post - the main problem was that we were starting on a bad basis. The problem of having to apply a factor of 1.5 stemmed from the fact that we were not using the height and width information from the canvas, but rather the containing control. Big oops. Once we got that straight, things fell into place.

    Additionally, in the code I posted (for anyone reading - do not use :) ), we also are not yet taking into account the aspect ratio of the images.

    The bottom line is that everyone facing this issue should use AlexP's article. I just initially missed that it is the full solution.

    Thanks again AlexP!

  • AlexPAlexP ✭✭ Member ✭✭
    Thank you for your kind words!
    Glad to help! :smile:
  • CarLoOSXCarLoOSX ✭✭ USMember ✭✭

    @AlexP said:
    Recently, I was facing similar problem.
    Ended up creating a generic control for SVG icons.
    Check my blog post about it: Using SVG images with SkiaSharp

    Hope it helps! :smile:

    very useful, better than ffimageloading svg if you want only to load simple svg images.

Sign In or Register to comment.