-1

I have the following class with a nested async function, however, somehow the line

await Jimp.loadFont(font)

doesn't block the loop from executing, instead the following source code gives the output

2
3
index 0 start
index 0 about to loadFont xxxxxx
index 0 start
index 0 about to loadFont xxxxx
/* crash due to this unintended async behavior */

I want it to wait until Jimp has loaded the font, i.e. the ideal output is

2
3
index 0 start
index 0 about to loadFont xxxxxx
index 0 loadFont start
index 0 loadFont end
index 0 loadFont end
index 1 start
index 1 about to loadFont xxxxxx
index 1 loadFont start
index 1 loadFont end
index 1 loadFont end
index 2 start
index 2 about to loadFont xxxxxx
index 2 loadFont start
index 2 loadFont end
index 2 loadFont end
/* repeat for 1 more time as inputGif.frames.length = 2 */

Here is the source

export class GifWriter {
    async writeTextOnGif(options: GifWriterOptions) {
        let src = this.getSrc(options.src);
        let dest = options.dest;
    
        var frames: GifFrame[] = [];
    
        await GifUtil.read(src).then(async inputGif => {

            console.log(inputGif.frames.length);
            console.log(options.text_options.length);

            inputGif.frames.forEach(async frame => {
                var jimpCopied = GifUtil.copyAsJimp(Jimp, frame);

                for (var index = 0; index < options.text_options.length; index++) {

                    console.log(`index ${index} start`);

                    let text = options.text_options[index].text;
                    let font = this.getFont(options.text_options[index].font_path, options.text_options[index].font_color, options.text_options[index].font_size);
                    let alignmentX = this.getAlignmentX(options.text_options[index].alignmentX);
                    let alignmentY = this.getAlignmentY(options.text_options[index].alignmentY);
                    let positionX = options.text_options[index].positionX;
                    let positionY = options.text_options[index].positionY;
                    // print(font, x axis offset, y axis offset, text options, maxWidth, maxHeight)
                    let [offsetX, offsetY, maxWidth, maxHeight] = this.getPosition(jimpCopied, positionX, positionY);

                    console.log(`index ${index} about to loadFont ${font}`);

                    await Jimp.loadFont(font).then(font => {
                        console.log(`index ${index} loadFont start`);
                        jimpCopied.print(font, offsetX, offsetY, {
                            text: text,
                            alignmentX: alignmentX,
                            alignmentY: alignmentY
                            },
                            maxWidth,
                            maxHeight);
                        console.log(`index ${index} end`);
                    });
                    console.log(`index ${index} end`);
                }
                console.log(`create GifFrame`);
                const GifCopied = new GifFrame(jimpCopied.bitmap,{
                    disposalMethod: frame.disposalMethod,
                    delayCentisecs: frame.delayCentisecs,
                });
                GifUtil.quantizeSorokin(GifCopied, 256);
                frames.push(GifCopied); 
            });
        });
        // write to the destination file.
        GifUtil.write(dest, frames);
    }

My guess is inputGif.frames.forEach(async frame => { is making the execution for each frame async? But if I remove the async keyword then I can't use await with Jimp.loadFont, could someone give an advice on how can I achieve the intended output?

Stephen Fong
  • 697
  • 5
  • 17

1 Answers1

1

Async/Await works with for loop, it doesn't work as expected with forEach loop. So, i've made some edits to the code and used for loop in place of forEach. Here is the updated code, try this approach once

async writeTextOnGif(options: GifWriterOptions) {
  let src = this.getSrc(options.src);
  let dest = options.dest;

  var frames: GifFrame[] = [];

  let inputGif = await GifUtil.read(src);

  console.log(inputGif.frames.length);
  console.log(options.text_options.length);

  for (let parentLoopIndex = 0, len = inputGif.frames.length; parentLoopIndex < len; parentLoopIndex++) {
    let frame = inputGif.frames[parentLoopIndex];
    var jimpCopied = GifUtil.copyAsJimp(Jimp, frame);
    let promise; 
    for (var childLoopIndex = 0; childLoopIndex < options.text_options.length; childLoopIndex++) {

        console.log(`index ${childLoopIndex} start`);
        /* To keep it short, i've removed some code in the asnwer. */
        let newFont = await Jimp.loadFont(font);
        console.log(`index ${childLoopIndex} loadFont start`);
        jimpCopied.print(newFont, offsetX, offsetY, {
            text: text,
            alignmentX: alignmentX,
            alignmentY: alignmentY
            },
            maxWidth,
            maxHeight);
        console.log(`index ${childLoopIndex} end`);
    }
    console.log(`create GifFrame`);
    const GifCopied = new GifFrame(jimpCopied.bitmap,{
        disposalMethod: frame.disposalMethod,
        delayCentisecs: frame.delayCentisecs,
    });
    GifUtil.quantizeSorokin(GifCopied, 256);
    frames.push(GifCopied); 
  }

  // write to the destination file.
  GifUtil.write(dest, frames);
}
Raj Kumar N
  • 783
  • 6
  • 22