This tutorial is a part of the 'How to Develop Function Compute' series. It's a comprehensive guide that illustrates a step-by-step approach to port Ghostscript to FunctionCompute.

Preface

First, let's take a quick look at several key concepts mentioned in this article:
  • Function Compute: It's an event-driven service that allows users to focus on writing and uploading code without the need to manage infrastructure such as servers. Function Compute provides compute resources, allowing users to run code more elastically by just paying for the resources consumed while running the code. For more information about Function Compute, see here.
  • Fun: Also known as Funcraft, is a developer tool for serverless applications that helps in managing resources such as Function Compute, API Gateway, and Log Service. Use Fun to develop, build, and deploy resources by defining specified resources in the template.yml file. For more information about Fun, see here.
  • Ghostscript: It's a suite of software based on an interpreter for Adobe Systems' PostScript and Portable Document Format (PDF) page description languages.
Note The operations in this article are applicable to Fun version 3.0.0-beta.2 and all later versions.

Dependent Tools

This project is developed based on MacOS. However, the tools involved are platform independent and also applicable to the Linux and Windows operating systems. Before proceeding with the example, make sure that the following tools are correctly installed, updated to the latest version, and properly configured.

Fun is based on Docker to simulate the local environment.

MacOS users may use homebrew to install these tools:
brew cask install docker
brew tap vangie/formula
brew install fun

Windows and Linux users must read this article to successfully install these tools.

After the installation, first run the fun config command to initialize the configuration.
Note Make sure to use a Fun version 3.0.0-beta.2 or any later version.
fun --version
3.0.0-beta.2

Convert PDF Files to JPG Files in Linux

The default Linux environment of Function Compute is Debian Jessie. To convert PDF files to JPG files in the Debian Jessie environment, run the fun install sbox command to start a sandbox environment and perform the following operations.
fun install sbox -r nodejs10 -i
root@fc-nodejs10:/code# apt-get update && apt-get install -y ghostscript
....
root@fc-nodejs10:/code# ls
test.pdf
root@fc-nodejs10:/code# gs -sDEVICE=jpeg -dTextAlphaBits=4 -r144 -o test.jpg test.pdf
GPL Ghostscript 9.26 (2018-11-20)
Copyright (C) 2018 Artifex Software, Inc.  All rights reserved.
This software comes with NO WARRANTY: see the file PUBLIC for details.
Processing pages 1 through 1.
Page 1
root@fc-nodejs10:/code# ls
test.jpg  test.pdf
The command for the conversion is gs -sDEVICE=jpeg -dTextAlphaBits=4 -r144 -o test.jpg test.pdf. The options in the command are as follows:
  • -sDEVICE=jpeg: Specifies the output device as jpeg. The other optional value is jpeggray.
  • -o: Specifies the output file.
  • -dTextAlphaBits: Specifies the text sampling antialiasing.
  • -dGraphicsAlphaBits: Specifies the image sampling antialiasing.
  • -r144: Sets the dpi of the picture to 14.

For more options, visit Devices

Port the Conversion Result to Function Compute

To port the conversion result of Ghostscript in the sandbox to the Node.js 10 runtime of Function Compute, initialize a local Fun project to install, debug, pack, and upload the dependency locally.

  • Initialize a Project
    fun init event-nodejs10
    Start rendering template...
    + /Users/vangie/Desktop/test
    + /Users/vangie/Desktop/test/.funignore
    + /Users/vangie/Desktop/test/index.js
    + /Users/vangie/Desktop/test/template.yml
    finish rendering template.
    Update the content of the template.yml file as shown below.
    ROSTemplateFormatVersion: '2015-09-01'
    Transform: 'Aliyun::Serverless-2018-04-03'
    Resources:
      ghostscript:
        Type: 'Aliyun::Serverless::Service'
        Properties:
          Description: 'helloworld'
        pdf2jpg:
          Type: 'Aliyun::Serverless::Function'
          Properties:
            Handler: index.handler
            Runtime: nodejs10
            CodeUri: './'
            EnvironmentVariables:
              GS_LIB: ".fun/root/usr/share/ghostscript/9.26/Resource/Init:\
                .fun/root/usr/share/ghostscript/9.26/lib:\
                .fun/root/usr/share/ghostscript/9.26/Resource/Font:\
                .fun/root/usr/share/ghostscript/fonts:\
                .fun/root/var/lib/ghostscript/fonts:\
                .fun/root/usr/share/ghostscript/fonts:\
                .fun/root/usr/share/fonts"

    The environment variable GS_LIB is required to install Ghostscript in the code directory.

    Update the content of the index.js file as shown below.
    const { exec } = require('child_process');
    
    module.exports.handler = function (event, context, callback) {
      const cmd = 'gs -sDEVICE=jpeg -dTextAlphaBits=4 -r144 -o /tmp/test.jpg test.pdf';
      exec(cmd, (err, stdout, stderr) => {
        if (err) {
          console.log(stdout);
          console.log(stderr);
          callback(err, "convert fail.\n");
        } else {
          console.log(stdout)
          callback(null, 'convert success.\nJPG file save to /tmp/test.jpg\n');
        }
      });
    };
  • Install Ghostscript
    Run the following command to install Ghostscript.
    fun install -p apt -r nodejs10 ghostscript --save
    Ghostscript is installed in the .fun directory of the current directory.
    tree . -a -L 4
    .
    ©À©¤©¤ .fun
    ©¦   ©¸©¤©¤ root
    ©¦       ©À©¤©¤ etc
    ©¦       ©¦   ©À©¤©¤ fonts
    ©¦       ©¦   ©À©¤©¤ ghostscript
    ©¦       ©¦   ©¸©¤©¤ libpaper.d
    ©¦       ©À©¤©¤ usr
    ©¦       ©¦   ©À©¤©¤ bin
    ©¦       ©¦   ©À©¤©¤ lib
    ©¦       ©¦   ©À©¤©¤ sbin
    ©¦       ©¦   ©¸©¤©¤ share
    ©¦       ©¸©¤©¤ var
    ©¦           ©¸©¤©¤ lib
    ©À©¤©¤ .funignore
    ©À©¤©¤ README.md
    ©À©¤©¤ fun.yml
    ©À©¤©¤ index.js
    ©¸©¤©¤ template.yml
    
    16 directories, 7 files

Call the Function Locally

Create a test.pdf file in the code directory.
tree          
.
©À©¤©¤ README.md
©À©¤©¤ fun.yml
©À©¤©¤ index.js
©À©¤©¤ template.yml
©¸©¤©¤ test.pdf
Run the fun local invoke command to call the function locally.
fun local invoke pdf2jpg     
using template: template.yml
FC Invoke Start RequestId: 3ea14d81-fd6b-4259-b9a5-dde29c2f022a
load code for handler:index.handler
2019-09-03T07:36:20.200Z 3ea14d81-fd6b-4259-b9a5-dde29c2f022a [verbose] stdout =================== START
2019-09-03T07:36:20.200Z 3ea14d81-fd6b-4259-b9a5-dde29c2f022a [verbose] GPL Ghostscript 9.26 (2018-11-20)
Copyright (C) 2018 Artifex Software, Inc.  All rights reserved.
This software comes with NO WARRANTY: see the file PUBLIC for details.
Warning: the map file cidfmap was not found.
Processing pages 1 through 1.
Page 1

2019-09-03T07:36:20.201Z 3ea14d81-fd6b-4259-b9a5-dde29c2f022a [verbose] stdout =================== END
FC Invoke End RequestId: 3ea14d81-fd6b-4259-b9a5-dde29c2f022a
convert success.
JPG file save to /tmp/test.jpg
2019-09-03T07:36:20.212Z 3ea14d81-fd6b-4259-b9a5-dde29c2f022a [error](node:23) [DEP0005] DeprecationWarning: Buffer() is deprecated due to security and usability issues. Please use the Buffer.alloc(), Buffer.allocUnsafe(), or Buffer.from() methods instead.


RequestId: 3ea14d81-fd6b-4259-b9a5-dde29c2f022a          Billed Duration: 1590 ms        Memory Size: 1998 MB    Max Memory Used: 32 MB
Find the generated test.jpg file in the .fun/tmp/invoke directory.
tree .fun/tmp/invoke -L 3
.fun/tmp/invoke
©¸©¤©¤ ghostscript
    ©¸©¤©¤ pdf2jpg
        ©À©¤©¤ agenthubout.log
        ©¸©¤©¤ test.jpg

Deploy and Call the Function

Now run the fun deploy command to quickly deploy Ghostscript to Function Compute.
fun deploy              
using template: template.yml
using region: cn-shanghai
using accountId: ***********4733
using accessKeyId: ***********EUz3
using timeout: 60

Waiting for service ghostscript to be deployed...
        Waiting for function pdf2jpg to be deployed...
                Waiting for packaging function pdf2jpg code...
                package function pdf2jpg code done, the number of files you have packaged is£º1048
        function pdf2jpg deploy success
service ghostscript deploy success
Lastly, run the fun invoke <function_name> command to call the function.
fun invoke pdf2jpg
using template: template.yml
========= FC invoke Logs begin =========
FC Invoke Start RequestId: 99cc8b32-6084-4a6b-a1ff-444e06e10eca
load code for handler:index.handler
2019-09-03T07:49:47.454Z 99cc8b32-6084-4a6b-a1ff-444e06e10eca [verbose] stdout =================== START
2019-09-03T07:49:47.455Z 99cc8b32-6084-4a6b-a1ff-444e06e10eca [verbose] GPL Ghostscript 9.26 (2018-11-20)
Copyright (C) 2018 Artifex Software, Inc.  All rights reserved.
This software comes with NO WARRANTY: see the file PUBLIC for details.
Warning: the map file cidfmap was not found.
Processing pages 1 through 1.
Page 1

2019-09-03T07:49:47.455Z 99cc8b32-6084-4a6b-a1ff-444e06e10eca [verbose] stdout =================== END
FC Invoke End RequestId: 99cc8b32-6084-4a6b-a1ff-444e06e10eca

Duration: 526.16 ms, Billed Duration: 600 ms, Memory Size: 128 MB, Max Memory Used: 57.09 MB
========= FC invoke Logs end =========

FC Invoke Result:
convert success.
JPG file save to /tmp/test.jpg