Issue with a Pre-installed service (Sharp) on Backendless

Hello team,

This is in reference to the pre-installed service (Sharp) available for image processing.

Back Story:
I started to use this over a year ago to put some text over images.
While I could control the font size, bold/ normal, color of the text, the font itself I was not able to change. I continued to use as it was not not of immediate concern at that time.

In Oct 2023, there was a separate more concerning issue introduced (due to backendless upgrade of Nodejs in CloudCode env from 14.x to 18.x). I had raised this issue here and the team promptly fixed it:

Though I had mentioned that font issue in that thread itself, I was happy that more concerning issue was addressed quickly by the team. The sharp library installation still did not allow for font change. (The library itself definitely supports it). It always defaulted to one particular font.

Current issue:
Between 8-Feb-24 and 21-Feb-24, that defaulted particular font has changed.
This has caused my design to change.


Before


After

This change in default font has impacted posts that I send to clients.

Current ask:
Please resolve the ability to change the font instead of relying on default.

Here is the test code:
My application ID is 0B6BE4AB-12E6-4BF7-FF0C-CDFE694EF000

I have created a service FHSharpTestLib in js with a method that takes a white image and tries to write two lines over a colored background with different fonts and colors.
test_sharp_js.txt (2.6 KB)

The svg buffer printed on console shows the 2 different fonts as below:

But, after compositing using the sharp library, the output image does not have the 2 different fonts instead it has the defaulted font.

Few references
My research had led me to below links that I want to share as possible solutions. But, I am not an expert in this. Just sharing in case it could shorten turn around time.
They point towards setting up environment for fonts required by the sharp library.

1.font installation note at sharp lib
https://sharp.pixelplumbing.com/install#fonts

  1. librsvg uses fontconfig, which can be controlled via environment variables and config files - see https://www.freedesktop.org/software/fontconfig/fontconfig-user.html

  2. a short post about how to fix it here:
    How to install custom fonts on a nodejs image using fontconfig | Constant Solutions

Kindly help me resolve this issue as early as possible.
I would really appreciate it.

Hi @Achilles_Pereira

First of all, thank you for such a detailed topic and for providing additional links that helped us.

According to the default font I completely agree with, because we constantly upgrade our basic image and the default font might be changed there so I can not recommend relying on it.

Well, seems like using custom fonts is the way to go.
Although the fix is not on the prod yet (I guess it will be available in a few days) here are the instructions I went through while fixing the issue:

Entire Code:

const path = require('path')
const sharp = require('sharp')

const APP_FILES_PATH = path.resolve(__dirname, '../../../../../') // .../your-app-id/files
const FONTS_DIR_PATH = path.resolve(APP_FILES_PATH, './test/fonts') // absolute path to your fonts
const CANVAS_FILE_PATH = path.resolve(APP_FILES_PATH, './test/canvas.jpg')

process.env.FONTCONFIG_PATH = FONTS_DIR_PATH // override path to fonts config file

console.log('FONTS_DIR_PATH', FONTS_DIR_PATH) // IMPORTANT! copy the entire path and put it into the fonts.conf file

class FHSharpTestLib {
  /**
   * @returns {String}
   */
  async getImage() {
    const svgPostLine1Height = 50
    const svgPostLine2Height = 50
    const line1px = '22px'
    const line2px = '22px'
    const line1HexVal = '#595959'
    const line2HexVal = '#ff0000'
    const line1Style = 'bold'
    const line2Style = 'normal'
    const postLine1 = 'This is Line 01. bold and gray ' + new Date().toLocaleTimeString()
    const postLine2 = 'This is Line 02. normal and red'
    const svgLineWidth = 612
    const rightTextOffset = 10

    const svgPostLine1 = `
              <svg width="${ svgLineWidth }" height="${ svgPostLine1Height }">
              <rect x="0" y="0" width="100%" height="100%" fill="lightpink" opacity="1"/>
              <text x="${ rightTextOffset }" y="80%" font-family = "Tacoma" font-size = "${ line1px }" fill = "${ line1HexVal }" font-weight="${ line1Style }" text-anchor="start" class="title"><![CDATA[${ postLine1 }]]></text>
              </svg>`

    const svgPostLine2 = `
              <svg width="${ svgLineWidth }" height="${ svgPostLine2Height }">
              <rect x="0" y="0" width="100%" height="100%" fill="lightpink" opacity="1"/>
              <text x="${ rightTextOffset }" y="65%" font-family = "Arialn" font-size = "${ line2px }" fill = "${ line2HexVal }" font-weight= "${ line2Style }" text-anchor="start" class="title"><![CDATA[${ postLine2 }]]></text>
              </svg>`

    console.log(svgPostLine1)
    console.log(svgPostLine2)

    const svgLine1 = Buffer.from(svgPostLine1)
    const svgLine2 = Buffer.from(svgPostLine2)

    const imgBuffer = await sharp(CANVAS_FILE_PATH)
      .composite([
        {
          input: svgLine1,
          top  : 200,
          left : 100,
        },
        {
          input: svgLine2,
          top  : 400,
          left : 100,
        },
      ])
      .png()
      .toBuffer()

    const fileURL = await Backendless.Files.saveFile('/test', 'new-img.png', imgBuffer, true)

    const html = `<img src="${ fileURL }" alt="${ new Date() }"/>`

    this.response.headers['Content-Type'] = 'text/html'

    return html
  }

}

Backendless.ServerCode.addService(FHSharpTestLib)

  1. need to get the absolute path to your app file, the best way is to retrieve using relative back path const APP_FILES_PATH = path.resolve(__dirname, '../../../../../')
  2. then you need to compose absolute paths for canvas and fonts directory
const FONTS_DIR_PATH = path.resolve(APP_FILES_PATH, './test/fonts')
const CANVAS_FILE_PATH = path.resolve(APP_FILES_PATH, './test/canvas.jpg')
  1. print the FONTS_DIR_PATH value, we will need it a little bit later
  2. set the following env process.env.FONTCONFIG_PATH = FONTS_DIR_PATH to override the path for the fontsconfig package which is responsible for delivering fonts
  3. deploy the code
  4. open RealTime Log
  5. run the service method, it might fail and it’s OK until we compiled configuring fonts
  6. in the RT Log copy the FONTS_DIR_PATH value
  7. go to Files Browser and open the folder with your custom fonts
  8. create a new file fonts.conf and add the following content in it and save:
<?xml version="1.0"?>
<!DOCTYPE fontconfig SYSTEM "fonts.dtd">
<fontconfig>
	<dir>FONTS_DIR_PATH value from the point 8</dir>
	<config></config>
</fontconfig>
  1. run the service again, now it should work as expected

Regards,
Vlad

Thank you @vladimir-upirov
It was step-by-step. Very clear.

Fantastic support from Backendless.

Hello @Achilles_Pereira

We’ve just updated cloud servers with a fix for the issue you described above. Could you kindly let us know whether fix works for you well?

Regards,
Inna