All files / roosterjs-content-model-plugins/lib/imageEdit/utils generateDataURL.ts

94.12% Statements 32/34
84.38% Branches 27/32
100% Functions 1/1
94.12% Lines 32/34

Press n or j to go to the next uncovered block, b, p or k for the previous block.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 791x                           1x 4x 4x                           36x 4x 4x 4x 4x 4x 4x 4x 4x 4x   4x 4x 4x 4x     4x 4x 8x 4x 4x   4x   4x 4x 4x 4x 4x 4x 4x                       4x          
import { getGeneratedImageSize } from './generateImageSize';
import type { ImageMetadataFormat } from 'roosterjs-content-model-types';
 
/**
 * @internal
 * Generate new dataURL from an image and edit info
 * @param image The image to generate data URL from. It is supposed to have original src loaded
 * @param editInfo Edit info of the image
 * @returns A BASE64 encoded string with image prefix that represents the content of the generated image.
 * If there are rotate/crop/resize info in the edit info, the generated image will also reflect the result.
 * It is possible to throw exception since the original image may not be able to read its content from
 * the code, so better check canRegenerateImage() of the image first.
 * @throws Exception when fail to generate dataURL from canvas
 */
export function generateDataURL(image: HTMLImageElement, editInfo: ImageMetadataFormat): string {
    const generatedImageSize = getGeneratedImageSize(editInfo);
    Iif (!generatedImageSize) {
        return '';
    }
 
    const {
        angleRad,
        widthPx,
        heightPx,
        bottomPercent,
        leftPercent,
        rightPercent,
        topPercent,
        naturalWidth,
        naturalHeight,
    } = editInfo;
    const angle = angleRad || 0;
    const left = leftPercent || 0;
    const right = rightPercent || 0;
    const top = topPercent || 0;
    const bottom = bottomPercent || 0;
    const nHeight = naturalHeight || image.naturalHeight;
    const nWidth = naturalWidth || image.naturalHeight;
    const width = widthPx || image.clientWidth;
    const height = heightPx || image.clientHeight;
 
    const imageWidth = nWidth * (1 - left - right);
    const imageHeight = nHeight * (1 - top - bottom);
    const doc = image.ownerDocument;
    const win = doc.defaultView;
 
    // Adjust the canvas size and scaling for high display resolution
    const devicePixelRatio = win?.devicePixelRatio || 1;
    const canvas = doc.createElement('canvas');
    const { targetWidth, targetHeight } = generatedImageSize;
    canvas.width = targetWidth * devicePixelRatio;
    canvas.height = targetHeight * devicePixelRatio;
 
    const context = canvas.getContext('2d');
 
    try {
        Eif (context) {
            context.scale(devicePixelRatio, devicePixelRatio);
            context.translate(targetWidth / 2, targetHeight / 2);
            context.rotate(angle);
            context.scale(editInfo.flippedHorizontal ? -1 : 1, editInfo.flippedVertical ? -1 : 1);
            context.drawImage(
                image,
                nWidth * left,
                nHeight * top,
                imageWidth,
                imageHeight,
                -width / 2,
                -height / 2,
                width,
                height
            );
        }
        return canvas.toDataURL('image/png', 1.0);
    } catch {
        return image.src;
    }
}