2

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?

Dylan Cristy
  • 916
  • 11
  • 29
  • What if you put only the `height` parameter and the other you let `null` ? – V. Sambor Mar 04 '20 at 20:26
  • But I'm saying I know neither the height or width, all I have is an `ArrayBuffer` which is binary data. I have no insight into the properties of the image such as height or width. But once the image is "rendered" by Word, it should be aware of the image's natural height and width because that must be apparent after using the binary data to reconstruct the image. – Dylan Cristy Mar 04 '20 at 20:44
  • Yes, I got it, but at one point you said it is defaulting to 100x100 and I was thinking what would the result be if you add one just of the properties width/height ??? – V. Sambor Mar 04 '20 at 20:54

1 Answers1

1

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
ijavid
  • 715
  • 12
  • 23