ImageMagick icon indicating copy to clipboard operation
ImageMagick copied to clipboard

MagickWand: significant performance drop when stroking paths with scale > 1

Open IKupriyanov-HORIS opened this issue 4 months ago • 3 comments

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): Image

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. Image

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.

Image

Steps to Reproduce

These images are automatically generated by our library. The MVG is dumped using the DrawGetVectorGraphics function.

DrawCircle test:

  1. Unzip circle_50000.zip
  2. Run magick -size 600x400 mvg:./circle_50000.mvg circle_50000.png
    Result: conversion takes acceptable time, like ~5 seconds (could be better, though?)
  3. Unzip [email protected]
  4. Run magick -size 1200x800 mvg:./[email protected] [email protected] Result: conversion takes unacceptable 40+ seconds, yet the only difference is the affine 2 0 0 2 0 0 at the beginning of the file.

DrawPath* test:

  1. Unzip path_10000.zip
  2. Run magick -size 800x400 mvg:./path_10000.mvg path_10000.png Result: converted in zero seconds.
  3. Unzip [email protected]
  4. 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 the affine 2 0 0 2 0 0 at the beginning of the file.

Images

circle_50000.zip [email protected] path_10000.zip [email protected]

IKupriyanov-HORIS avatar Nov 13 '25 19:11 IKupriyanov-HORIS

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?

snibgo avatar Nov 14 '25 01:11 snibgo

[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.

stroke.zip stroke2x.zip

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.

IKupriyanov-HORIS avatar Nov 14 '25 20:11 IKupriyanov-HORIS

... 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.

IKupriyanov-HORIS avatar Nov 17 '25 20:11 IKupriyanov-HORIS