sharp icon indicating copy to clipboard operation
sharp copied to clipboard

Slow processing with composite SVG which contains <text>

Open robinparisi opened this issue 3 years ago • 9 comments

Hi,

I'm trying to add a text to my picture by using composite API and an SVG wich contains a <text> element. When I remove <text>, or try with a simple SVG, the process only takes a few ms (< 10ms) for one picture. As soon as I add a <text> element, it takes many seconds (> 7s) to process. Below a simple example with a measurment of execution time.

const sharp = require('sharp')

;(async () => {
  const overlay = `<svg width="200" height="200">
    <text x="50%" y="50%" font-family="sans-serif" dominant-baseline="middle" font-size="30" text-anchor="middle">Lorem ipsum</text>
    </svg>`

  console.time('createimage')
  await sharp(
    {
      create: {
        width: 200,
        height: 200,
        channels: 4,
        background: { r: 216, g: 216, b: 216 }
      }
    })
    .composite([{
      input: Buffer.from(overlay),
      gravity: 'center'
    }])
    .png()
    .toFile('test.png')

  console.timeEnd('createimage')
})()

With result:

createimage: 7.377s

Informations:

  Sharp : [email protected]
  System:
    OS: macOS Mojave 10.14.6
    CPU: (12) x64 Intel(R) Core(TM) i7-8700B CPU @ 3.20GHz
    Memory: 155.33 MB / 16.00 GB
    Shell: 5.3 - /bin/zsh
  Binaries:
    Node: 14.18.1 - ~/.nvm/versions/node/v14.18.1/bin/node
    npm: 6.14.15 - ~/.nvm/versions/node/v14.18.1/bin/npm

Interesting point: I've tried the same code on a colleague's mac computer with M1 chip and it took only ~70ms to process (and ~5ms without <text> element).

I'm not sure it's directly related to this lib, I saw a few issues with SVG but none wich implies <text> in the process with the composite API.

robinparisi avatar Nov 22 '21 17:11 robinparisi

Hi, this sample code fails with Error: Image to composite must have same dimensions or smaller.

If I change height="1000" to height="200", or change height: 200 to height: 1000, so the dimensions match, I consistently see times all below 30ms.

Are you using the prebuilt libvips binaries provided by sharp? Perhaps you've installed the vips package via Homebrew? If the latter, it's possible there's a problem with font discovery on your machine.

lovell avatar Nov 23 '21 10:11 lovell

Hey @lovell, thanks for the response.

You're absolutely right, there is an error with SVG height, I've edited the code.

Based on this page https://sharp.pixelplumbing.com/install, I've installed the lib with a simple npm i sharp so I'm using the prebuilt version of libvips. I've checked Homebrew and no version is installed locally.

Edit: Is it possible than other libs installed locally like libpng can interfere with Sharp? I'm not sure it's related but I prefere to check.

robinparisi avatar Nov 24 '21 13:11 robinparisi

In my MacBook: createimage: 1.097s

image

yisibl avatar Dec 27 '21 17:12 yisibl

@robinparisi Were you able to make any progress with this?

lovell avatar Jan 24 '22 12:01 lovell

@lovell I couldn't find any reason at the moment. I've tried on multiple mac mini and except for the M1 one (wich is really fast anyway), it always takes more time with SVG text, by oposition to simple SVG with no text which is way faster.

I've also tried with node v16.13.2 :

Capture d’écran 2022-01-24 à 18 43 03

robinparisi avatar Jan 24 '22 17:01 robinparisi

Please can you profile this script via a tool such as callgrind.

Install via brew install valgrind then run via valgrind --tool=callgrind node main.js - this will produce a file called callgrind.out.xxxx

Please can you provide the output of running callgrind_annotate callgrind.out.xxxx

lovell avatar Jan 26 '22 13:01 lovell

Quick thought: do you have fontconfig installed? You can do this via brew install fontconfig if not. This might make font discovery faster as it will cache filesystem lookups.

lovell avatar Jan 31 '22 08:01 lovell

So, I had over 2000 fonts. I've tried to uninstall all my custom fonts and run the test script again. Execution time dropped under 500 ms. It seems that execution time is correlated to the number of fonts available (fontconfig is installed)

test-fonts

PS: I'm not sure I can install Valgrind from brew (not sure why atm)

valgrind

robinparisi avatar Feb 02 '22 01:02 robinparisi

Thanks for the update, this does sound like font discovery is the problem.

I hadn't realised valgrind is unavailable for macOS via homebrew, sorry. You might be able to use kcachegrind, which appears to be available via MacPorts - https://github.com/macports/macports-ports/tree/master/kde/kcachegrind4

lovell avatar Feb 03 '22 21:02 lovell

Closing as there's probably nothing we can do in sharp for this. fontconfig provides the fc-cache tool to build a cache of fonts so it doesn't have to "discover" them each time, which might help.

lovell avatar Aug 24 '22 16:08 lovell