tom-weatherhead/thaw-image-processing.ts

View on GitHub
src/util/file-io.ts

Summary

Maintainability
A
0 mins
Test Coverage
// // thaw-image-processing.ts/src/util/file-io.ts

import * as fs from 'fs'; // Used only as a type, so Angular will be OK.

import * as jpg from 'jpeg-js';
import * as png from '@vivaxy/png';

import { createThAWImage, IThAWImage } from './image';

export interface IFileIOManager {
    load(path: string): Promise<IThAWImage>;
    save(image: IThAWImage, path: string): Promise<void>;
}

export function getExtensionFromFilePath(path: string): string {
    const i = path.toLowerCase().lastIndexOf('.');

    if (i < 0) {
        return '';
    }

    const extension = path.substring(i + 1);

    if (extension === 'jpeg') {
        return 'jpg';
    }

    return extension;
}

// Return an IThAWImage or a standard ImageData?

async function loadFile(
    fsInjected: typeof fs,
    path: string
): Promise<IThAWImage> {
    const extension = getExtensionFromFilePath(path);
    const srcData = await fsInjected.promises.readFile(path);
    let srcImage;

    switch (extension) {
        case 'jpg':
            srcImage = jpg.decode(srcData, { useTArray: true });
            break;

        case 'png':
            srcImage = png.decode(srcData);
            break;

        default:
            throw new Error(
                `loadFile() : Unsupported extension in path '${path}'`
            );
    }

    return createThAWImage(
        srcImage.width,
        srcImage.height,
        undefined,
        undefined,
        Uint8ClampedArray.from(srcImage.data)
    );
}

async function saveFile(
    fsInjected: typeof fs,
    image: IThAWImage,
    path: string
): Promise<void> {
    const defaultJpegQuality = 90;
    const extension = getExtensionFromFilePath(path);
    let dstData;

    switch (extension) {
        case 'jpg':
            dstData = jpg.encode(image, defaultJpegQuality).data;
            break;

        case 'png':
            dstData = png.encode({
                //     data: number[],
                data: Array.from(image.data),
                width: image.width,
                height: image.height,
                //     colorType: COLOR_TYPES,
                colorType: 2, // TRUE_COLOR; 3 channels
                depth: 8, // 8 bits per channel
                interlace: 0,
                compression: 0,
                filter: 0
                // , palette?: [number, number, number, number][]
            });
            break;

        default:
            throw new Error(
                `saveFile() : Unsupported extension in path '${path}'`
            );
    }

    await fsInjected.promises.writeFile(path, dstData);
}

export function createFileIOManager(fsInjected: typeof fs): IFileIOManager {
    // let dstImageQuality = defaultJpegQuality;

    return {
        load: (path: string) => loadFile(fsInjected, path),
        save: (image: IThAWImage, path: string) =>
            saveFile(fsInjected, image, path)
        // ,
        // getDstImageQuality: () => dstImageQuality,
        // setDstImageQuality: (newDstImageQuality: number) => {
        //     if (isLegalJpegImageQuality(newDstImageQuality)) {
        //         dstImageQuality = newDstImageQuality;
        //     }
        // }
    };
}