如何在文件上传校验器中获取图片文件的宽高?
实现图片文件的尺寸校验(获取图片宽高)
要获取File类型图片的宽高,需要通过Image对象异步加载图片资源——因为文件本身是二进制数据,只有加载后才能读取其原始尺寸。同时,由于这个操作是异步的,你需要把原有的同步校验器改成异步校验器(AsyncValidatorFn),适配Angular表单的异步校验逻辑。
核心实现思路
- 对每个图片文件,用
URL.createObjectURL()生成临时可访问的图片URL - 创建
Image实例并设置该URL为源,监听load事件获取图片的naturalWidth和naturalHeight(这两个属性是图片的原始宽高,不受CSS缩放影响) - 校验宽高是否超过设定的最大值,返回对应错误信息
- 加载完成后调用
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
相关产品推荐
相关产品推荐

