图片前置校验imageCheck

16 阅读1分钟
import { FileItem } from 'xxxUI';

type CompareCondition = 'equal' | 'greater' | 'less' | 'greaterOrEqual' | 'lessOrEqual';

interface CheckSizeParams {
  widthConform: boolean;
  heightConform: boolean;
  proportionConform: boolean;
  volumeConform: boolean;
}

// 校验图片
const checkImg =
  (checkSize: (width: number, height: number) => string) =>
  (prop: { fileList: FileItem[] }): Promise<any> => {
    const file = prop.fileList[0]; // 仅支持单图校验场景
    return new Promise((resolve, reject) => {
      const image = new Image();
      image.onload = (): void => {
        const { height: imgHeight, width: imgWidth } = image;
        const res = checkSize?.(imgWidth, imgHeight);
        if (!res) {
          return resolve({ autoRemove: false, shouldUpload: true });
        } else {
          // eslint-disable-next-line prefer-promise-reject-errors
          return reject({
            fileInstance: file.fileInstance,
            status: 'validateFail',
            shouldUpload: false,
            autoRemove: false,
            validateMessage: res,
          });
        }
      };
      image.onerror = function (): void {
        // eslint-disable-next-line prefer-promise-reject-errors
        reject({
          fileInstance: file.fileInstance,
          status: 'validateFail',
          shouldUpload: false,
          autoRemove: false,
          validateMessage: '图片加载失败,请重新上传',
        });
      };
      image.src = file.url || '';
    });
  };

// 校验图片规则
const imageSizeHint = (
  currentSzie: { width: number; height: number },
  expectSzie: { width?: number; height?: number },
  proportion?: [number, number],
  volume?: number,
  compareCondition?: CompareCondition,
  errorMessage?: string | ((params: CheckSizeParams) => string),
) => {
  const { width, height } = currentSzie;
  const { width: expectWidth, height: expectHeight } = expectSzie;
  const [expectWidthProportion = width, expectHeightProportion = height] = proportion || [];
  // 根据compareCondition动态选择比较运算符
  const compareOperators = {
    equal: (a: number, b: number) => a === b,
    greater: (a: number, b: number) => a > b,
    less: (a: number, b: number) => a < b,
    greaterOrEqual: (a: number, b: number) => a >= b,
    lessOrEqual: (a: number, b: number) => a <= b,
  };
  const compareFn = compareOperators[compareCondition || 'greaterOrEqual'];
  const widthConform = !expectWidth || compareFn(width, expectWidth);
  const heightConform = !expectHeight || compareFn(height, expectHeight);
  const proportionConform = !proportion || width / height === expectWidthProportion / expectHeightProportion;
  const volumeConform = !volume || width * height >= volume;

  if (widthConform && heightConform && proportionConform && volumeConform) {
    return '';
  } else {
    return (
      (typeof errorMessage === 'function'
        ? errorMessage({
            widthConform,
            heightConform,
            proportionConform,
            volumeConform,
          })
        : errorMessage) || '封面分辨率太低,请重新提交'
    );
  }
};

/**
 * description 校验图片尺寸 仅支持单图校验场景
 * @param needWidth 期望宽度
 * @param needHeight 期望高度
 * @param proportion 期望长宽比例
 * @param volume 期望像素
 * @param compareCondition 校验条件 'equal' | 'greater' | 'less' | 'greaterOrEqual' | 'lessOrEqual' -> CompareCondition
 * @param errorMessage 校验失败提示文案
 */

interface Params {
  needWidth?: number;
  needHeight?: number;
  proportion?: [number, number];
  volume?: number;
  compareCondition?: CompareCondition;
  errorMessage?: string | ((params: CheckSizeParams) => string);
}
export const checkImgSize = ({ needWidth, needHeight, proportion, volume, compareCondition, errorMessage }: Params) =>
  checkImg((width: number, height: number) =>
    imageSizeHint(
      { width, height },
      { width: needWidth, height: needHeight },
      proportion,
      volume,
      compareCondition,
      errorMessage,
    ),
  );