You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在文件上传校验器中获取图片文件的宽高?

实现图片文件的尺寸校验(获取图片宽高)

要获取File类型图片的宽高,需要通过Image对象异步加载图片资源——因为文件本身是二进制数据,只有加载后才能读取其原始尺寸。同时,由于这个操作是异步的,你需要把原有的同步校验器改成异步校验器(AsyncValidatorFn),适配Angular表单的异步校验逻辑。

核心实现思路

  1. 对每个图片文件,用URL.createObjectURL()生成临时可访问的图片URL
  2. 创建Image实例并设置该URL为源,监听load事件获取图片的naturalWidth和naturalHeight(这两个属性是图片的原始宽高,不受CSS缩放影响)
  3. 校验宽高是否超过设定的最大值,返回对应错误信息
  4. 加载完成后调用URL.revokeObjectURL()释放临时URL资源,避免内存泄漏

完整校验器代码

import { AbstractControl, AsyncValidatorFn, ValidationErrors } from '@angular/forms';
import { Observable, of } from 'rxjs';
import { switchMap } from 'rxjs/operators';

// 替换为你实际的常量定义
const VALIDATION_LABEL_ATTACHMENT_MAX_SIZE = '文件大小超过限制';
const VALIDATION_LABEL_IMAGE_DIMENSION = '图片尺寸超过限制';
const maxFileSize = 10 * 1024 * 1024; // 示例:10MB

export const filesDimensionValidator = (maxWidth: number, maxHeight: number): AsyncValidatorFn => {
  return (control: AbstractControl): Observable<ValidationErrors | null> => {
    const value: IUploadFileControl = control.value;

    if (!value?.allFiles?.length) {
      return of(null);
    }

    // 逐个校验文件
    const validateTasks = value.allFiles.map(file => {
      return new Observable<ValidationErrors | null>(observer => {
        // 保留原有的文件大小校验
        if (file.size > maxFileSize) {
          observer.next({ file_max_size: VALIDATION_LABEL_ATTACHMENT_MAX_SIZE });
          observer.complete();
          return;
        }

        // 仅处理图片类型文件
        if (!file.type.startsWith('image/')) {
          observer.next(null);
          observer.complete();
          return;
        }

        const img = new Image();
        img.src = URL.createObjectURL(file);

        img.onload = () => {
          URL.revokeObjectURL(img.src); // 释放临时URL资源
          // 校验尺寸
          if (img.naturalWidth > maxWidth || img.naturalHeight > maxHeight) {
            observer.next({ 
              file_invalid_dimension: VALIDATION_LABEL_IMAGE_DIMENSION,
              maxWidth,
              maxHeight,
              actualWidth: img.naturalWidth,
              actualHeight: img.naturalHeight
            });
          } else {
            observer.next(null);
          }
          observer.complete();
        };

        img.onerror = () => {
          URL.revokeObjectURL(img.src);
          // 图片加载失败时返回错误
          observer.next({ file_invalid_image: '无效的图片文件' });
          observer.complete();
        };
      });
    });

    // 合并校验结果:只要有一个文件不通过就返回错误
    return of(validateTasks).pipe(
      switchMap(tasks => {
        return new Observable<ValidationErrors | null>(observer => {
          let error: ValidationErrors | null = null;
          let completed = 0;

          tasks.forEach(task => {
            task.subscribe(result => {
              if (result && !error) {
                error = result;
                observer.next(error);
                observer.complete();
              }
              completed++;
              if (completed === tasks.length && !error) {
                observer.next(null);
                observer.complete();
              }
            });
          });
        });
      })
    );
  };
};

使用方式

在表单控件中,需要将校验器添加到asyncValidators数组(而非普通的validators):

this.uploadForm = this.formBuilder.group({
  files: ['', [], [filesDimensionValidator(1920, 1080)]] // 示例:限制最大1920x1080
});

内容的提问来源于stack exchange,提问作者Eugene Sukh

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.18 17:52:34