How to tell docx.js to use an image's natural height and width?

Viewed 1702

I'm getting an image's binary data as an ArrayBuffer, and inserting it into a document using docx.js:

getImageBinaryDataAsArrayBuffer().then(function (imageBuffer) {
    var doc = new docx.Document();
    var image = docx.Media.addImage(doc, imageBuffer);
    doc.addSection({
        children: [
            new docx.Paragraph({
                children: [image],
                alignment: docx.AlignmentType.CENTER
            }),
        ]
    });
    docx.Packer.toBlob(doc).then(function (blob) {
        // save the doc somewhere
    })
}).catch(function (err) {
    console.log(err);
});

This works, but it seems like the image size is defaulting to 100x100, and is not preserving the aspect ratio. In the docx.js documentation for Images, it looks like you can specify the height and width when you add the image to the doc:

Media.addImage(doc, [IMAGE_BUFFER], [WIDTH], [HEIGHT], [POSITION_OPTIONS]);

but I don't know the image's natural height and width since all I'm working with is an ArrayBuffer. (Can you determine an image's height and width from ArrayBuffer data? My gut says no...)

Is there a way to tell docx.js to use the image's natural height and width? Or at least to preserve the aspect ratio?

1 Answers

You can get the image dimension from the binary format as well. Here is my code which preserves aspect ratio when you need to resize the image to specific width/height

 import imageSize from 'image-size'; // https://www.npmjs.com/package/image-size
 
 function fitImage(doc, image, targetWidth?, targetHeight?) {
   
    const originalSize = imageSize(image);
    const originalAspectRatio = originalSize.width / originalSize.height;

    let width: number;
    let height: number;

    if (!targetWidth) {
        // fixed height, calc width
        height = targetHeight;
        width = height * originalAspectRatio;
    } else if (!targetHeight) {
        // fixed width, calc height
        width = targetWidth;
        height = width / originalAspectRatio;
    } else {
        const targetRatio = targetWidth / targetHeight;
        if (targetRatio > originalAspectRatio) {
            // fill height, calc width
            height = targetHeight;
            width = height * originalAspectRatio;
        } else {
            // fill width, calc height
            width = targetWidth;
            height = width / originalAspectRatio;
        }
    }

    console.log(originalSize, originalAspectRatio, width, height);

    return Media.addImage(doc, image, width, height);
}

const image = fitImage(doc, imageBuffer, 100); // set width to 100px calc height
const image = fitImage(doc, imageBuffer, null, height); // set height to 100px calc width
const image = fitImage(doc, imageBuffer, 100, 100); // fit image inside a 100x100 box
Related