MagickWand: significant performance drop when stroking paths with scale > 1
ImageMagick version
7.1.1-46
Operating system
Linux
Operating system, version and so on
Ubuntu 22.04 LTS
Description
We encountered some very strange behavior when drawing geometries.
Here is an example of what we want to draw (50_000 circles):
This works satisfactorily fast (about 4 seconds) in three out of four cases. But when the circle has a stroke and the scaling in the transformation is greater than one, there is a sharp drop in performance—drawing takes 44 seconds.
The situation is even worse if the circle is drawn using a path (arc with angle=2*PI). In this case, drawing 50,000 circles will not complete.
Steps to Reproduce
These images are automatically generated by our library. The MVG is dumped using the DrawGetVectorGraphics function.
DrawCircle test:
- Unzip circle_50000.zip
- Run
magick -size 600x400 mvg:./circle_50000.mvg circle_50000.png
Result: conversion takes acceptable time, like ~5 seconds (could be better, though?) - Unzip [email protected]
- Run
magick -size 1200x800 mvg:./[email protected] [email protected]Result: conversion takes unacceptable 40+ seconds, yet the only difference is theaffine 2 0 0 2 0 0at the beginning of the file.
DrawPath* test:
- Unzip path_10000.zip
- Run
magick -size 800x400 mvg:./path_10000.mvg path_10000.pngResult: converted in zero seconds. - Unzip [email protected]
- Run
magick -size 1200x800 mvg:./[email protected] [email protected]Result: conversion takes unacceptable 5 seconds to draw just 10_000 circles, yet the only difference is theaffine 2 0 0 2 0 0at the beginning of the file.
Images
circle_50000.zip [email protected] path_10000.zip [email protected]
I confirm the performance problem with IM v7.1.2-2.
I have experimented with your circle*.mvg, with a constant command:
magick -size 600x400 mvg:c.mvg c.png
... while varying the first "affine" in the SVG. With values between 1.0 and 1.21, it takes about 3 seconds. With values from 1.22 to 2.0, or 3.0, it takes about 220 seconds.
This sharp performance drop is weird.
Can you simplify the MVG? What minimal MVG has a sharp performance drop when the affine is changed by a small amount?
[UPDATED]: got tangled up with files
Can you simplify the MVG?
Here are the simplest MVG's. The only unnecessary part that I kept is the clip-path, but the duration is the same with or without it.
There are 2_500 points. The only difference is the transform. On my machine, the stroke2x.mvg is almost 4 times slower than stroke.mvg.
$ time magick -size 1200x800 mvg:./stroke.mvg stroke.png
real 0m0,169s
user 0m0,150s
sys 0m0,039s
$ time magick -size 1200x800 mvg:./stroke2x.mvg stroke2x.png
real 0m0,563s
user 0m0,589s
sys 0m0,043s
What minimal MVG has a sharp performance drop when the affine is changed by a small amount?
Based on my analysis, performance drops immediately, even with a single point. Due to exponential growth, this becomes more noticeable as the number of circles increases. The sharpness of the performance drop also depends on the computer and may vary.
... while varying the first "affine" in the SVG. With values between 1.0 and 1.21, it takes about 3 seconds. With values from 1.22 to 2.0, or 3.0, it takes about 220 seconds.
Good catch! Here is how we draw circles:
fill '#4A99D6'
stroke-width 1.6499999761581420898
stroke '#474747'
stroke-dasharray none
circle 394.654571533203125 119.70314788818359375 398.779571533203125 119.70314788818359375
stroke-width is 1.6499999761581420898.
With sacle 1.21 the actual stroke-width is 1.99649997115
With scale 1.22 the actual stroke-width is 2.01299997091
So the actual problem is a stroke-width with a value >= 2.