chrome-aws-lambda icon indicating copy to clipboard operation
chrome-aws-lambda copied to clipboard

fonts.conf file doesn't seem to be read when trying to disable anti-aliasing and font hinting

Open qboot opened this issue 3 years ago • 6 comments

Hi! I'm completely new to the serverless world and I'm trying to set up correctly my first lambda with puppeteer. Everything is working as expected. Kudos for this repo and how you maintain it 🙏 .

My issue is that I'm trying to disable all (system wide) fonts options: anti-aliasing, hinting, etc. with a fonts.conf file but it doesn't seem to work. My goal is to have a "pixel-perfect" screenshot.

I'm using the latest layer for my runtime (nodejs12.x) provided by shelfio, like that:

provider:
  name: aws
  layers:
    # https://github.com/shelfio/chrome-aws-lambda-layer
    - arn:aws:lambda:${self:provider.region}:764866452798:layer:chrome-aws-lambda:20
  # function parameters
  runtime: nodejs12.x
[...]
functions:
  run:
    handler: handler.run
    environment:
      FONTCONFIG_PATH: /var/task/fonts

And I've added a specific directory fonts in the lambda root code containing:

  • a font Verdana.ttf
  • a fonts.conf file:
<?xml version="1.0"?>
<!DOCTYPE fontconfig SYSTEM "fonts.dtd">
<fontconfig>
  <dir>/var/task/fonts/</dir>
  <match target="font">
    <edit name="rgba" mode="assign"><const>rgb</const></edit>
    <edit name="hinting" mode="assign"><bool>false</bool></edit>
    <edit name="antialias" mode="assign"><bool>false</bool></edit>
    <edit name="autohint" mode="assign"><bool>false</bool></edit>
    <edit name="hintstyle" mode="assign"><const>hintnone</const></edit>
    <edit name="lcdfilter" mode="assign"><const>lcdnone</const></edit>
  </match>
  <config></config>
</fontconfig>

Plus, I've added the FONTCONFIG_PATH: /var/task/fonts env var in the serverless.yml file. Verdana font is working well 👍 . But the screenshot still appear blurry. I've tested locally with the same fonts.conf file in Docker, and the screenshot is perfect, like I want.

The browser is instantiated like that:

const chromium = require('chrome-aws-lambda');
[...]
const browser = await chromium.puppeteer.launch({
    args: chromium.args,
    executablePath: await chromium.executablePath,
    defaultViewport: { width: 400, height: 300 },
});

Do you have any clue on why my fonts.conf is "partially read"? Or maybe something is overriding it in the runtime context of a lambda? Thanks!

EDIT: Oops, wrong tag. It's question not enhancement. Sorry

qboot avatar Nov 22 '20 18:11 qboot

Hello, it's me again!

I've just found what was causing my issue. 🤩 I first thought it was a fontconfig path issue, because the layer lives in /opt/nodejs or maybe it was a missing lib as you have compiled a lighter chromium. But not at all.

As we can see in my previous post, I'm calling puppeteer this way:

const chromium = require('chrome-aws-lambda');
[...]
const browser = await chromium.puppeteer.launch({
    args: chromium.args,
    executablePath: await chromium.executablePath,
    defaultViewport: { width: 400, height: 300 },
});

If we look for what are these args we can found the list in https://github.com/alixaxel/chrome-aws-lambda/blob/master/source/index.js#L83. I've tested each one separately.

And the culprit is:

if (this.headless === true) {
    result.push('--single-process');
}

I don't really understand the relation between this --single-process chromium flag and my fonts.conf not being respected, neither if this flag is really required here. But for now, I will just pass my own custom set of flags instead of calling the default one (args: chromium.args).

Thanks!

qboot avatar Nov 28 '20 10:11 qboot

Update. Even if it works well locally with a lambci/lambda:nodejs12.x Docker image from shelf.io. In real AWS environment the lambda timeout on const page = await browser.newPage(); when I remove the --single-process flag.

Back to square one 😕

qboot avatar Nov 28 '20 23:11 qboot

I too am stuck on this and the fonts I add are not being used/added in AWS runtime. Works fine locally using localstack but running the same in Lambda on AWS gives (what looks like) Open Sans even though font-face in CSS is Arial, Tahoma, Verdana but I've tried a bunch of different ones.

QAnders avatar Dec 18 '20 08:12 QAnders

Ok, a little progress... I did "force" it to use the /var/task/fonts path for fonts by changing this in source/index.js and the rebuilding:

if (['AWS_Lambda_nodejs10.x', 'AWS_Lambda_nodejs12.x'].includes(process.env.AWS_EXECUTION_ENV) === true) {
  //if (process.env.FONTCONFIG_PATH === undefined) {
    process.env.FONTCONFIG_PATH = '/var/task/fonts';
  //}

  if (process.env.LD_LIBRARY_PATH === undefined) {
    process.env.LD_LIBRARY_PATH = '/tmp/aws/lib';
  } else if (process.env.LD_LIBRARY_PATH.startsWith('/tmp/aws/lib') !== true) {
    process.env.LD_LIBRARY_PATH = [...new Set(['/tmp/aws/lib', ...process.env.LD_LIBRARY_PATH.split(':')])].join(':');
  }
}

And of cource added a fonts directory with a fonts.conf like:

<?xml version='1.0'?>
<!DOCTYPE fontconfig SYSTEM 'fonts.dtd'>
<fontconfig>
    <dir>/var/task/fonts/</dir>
    <cachedir>/tmp/fonts-cache/</cachedir>
    <alias>
        <family>Arial</family>
        <default>
            <family>DejaVu Sans</family>
        </default>
    </alias>

    <match target="font" >
        <edit mode="assign" name="autohint">  <bool>false</bool></edit>
        <edit mode="assign" name="hinting">   <bool>true</bool></edit>
        <edit mode="assign" name="hintstyle"> <const>hintfull</const></edit>
        <edit mode="assign" name="antialias"> <bool>true</bool></edit>
        <edit mode="assign" name="rgba">      <const>rgb</const></edit>
        <edit mode="assign" name="lcdfilter"> <const>lcdlight</const></edit>
    </match>

    <!-- smaller than 9px -->
    <match target="font">
        <test name="pixelsize" qual="any" compare="less"><double>9</double></test>
        <edit mode="assign" name="antialias"> <bool>false</bool></edit>
    </match>

    <!-- the below are noops for now -->

    <!-- bigger than 15px -->
    <match target="font">
        <test name="pixelsize" qual="any" compare="more"><double>15</double></test>
        <edit mode="assign" name="hintstyle"><const>hintfull</const></edit>
        <edit mode="assign" name="lcdfilter"><const>lcdlight</const></edit>
    </match>

    <!-- Bold fonts -->
    <match target="font">
        <test name="weight" compare="more"><const>medium</const></test>
        <edit mode="assign" name="hintstyle"><const>hintfull</const></edit>
        <edit mode="assign" name="lcdfilter"><const>lcdlight</const></edit>
    </match>

    <!-- Italic fonts -->
    <match target="font">
        <test name="slant"  compare="not_eq"><double>0</double></test>
        <edit mode="assign" name="hintstyle"><const>hintfull</const></edit>
        <edit mode="assign" name="lcdfilter"><const>lcdlight</const></edit>
    </match>

</fontconfig>

QAnders avatar Dec 21 '20 07:12 QAnders

@QAnders does it load the font config for you? I have the same setup as @qboot and loading fonts from the fonts folder works fine. But the settings of the fonts.conf file are never applied.

Firefox2005 avatar Dec 22 '20 17:12 Firefox2005

@alixaxel I can confirm that the 7.0.0 version fixes that problem! So this can be closed.

Firefox2005 avatar Feb 12 '21 18:02 Firefox2005