Проверка соотношения сторон изображения (ширина / высота) с помощью Yup и formik

#javascript #formik #yup

#javascript #formik #да

Вопрос:

Я пытаюсь выполнить проверку, используя yup для файла изображения, и я обнаружил, что https://github.com/formium/formik/issues/926 который проверяет только размер, а также тип файла.

и это текущая проверка yup, которую я использую

 file: lazy(value => {
    switch (typeof value) {
      case 'string':
        return string().required(errorHandler.requiredFile());
      default:
        return mixed()
          .required(errorHandler.requiredFile())
          .test(
            'fileSize',
            'Size',
            value => value amp;amp; value.size <= FILE_SIZE
          )
          .test(
            'fileType',
            'Format',
            value => value amp;amp; SUPPORTED_FORMATS.includes(value.type)
          )
    }
  }), 

Как я могу это сделать?

Ответ №1:

  1. создайте обещание, которое загрузит файл изображения и вернет размер
 const imageWidthAndHeight = (provideFile) => {
    // take the given file (which should be an image) and return the width and height
    const imgDimensions = { width: null, height: null };

    return new Promise(resolve => {
        const reader = new FileReader();
        
        reader.readAsDataURL(provideFile);
        reader.onload = function () {
            const img = new Image();
            img.src = reader.resu<

            img.onload = function () {
                imgDimensions.width = img.width;
                imgDimensions.height = img.height;

                resolve(imgDimensions);
            }
        };
    });
}
 
  1. Вызовите и дождитесь обещания в пользовательской функции yup (используя addMethod) и добавьте дополнительную проверку для проверки ширины и высоты.
 const imageDimensionCheck = Yup.addMethod(Yup.mixed, 'imageDimensionCheck', function (message, requiredWidth, requiredHeight) {
    return this.test("image-width-height-check", message, async function (value) {
        const { path, createError } = this;

        if (!value) {
            return;
        }

        const imgDimensions = await imageWidthAndHeight(value);

        if (imgDimensions.width !== requiredWidth) {
            return createError({
                path,
                message: `The file width needs to be the ${requiredWidth}px!`
              });
        }

        if (imgDimensions.height !== requiredHeight) {
            return createError({
                path,
                message: `The file height needs to be the ${requiredHeight}px!`
              });
        }

        return true;
    });
});
 
  1. Вызовите созданный метод Yup в formik
 <Formik
    initialValues={{
        bookCoverPhoto: null,
    }}

    validationSchema={
        Yup.object().shape({
            bookCoverPhoto: Yup.mixed()
                .required('You need to provide a file')
                .imageDimensionCheck('test', 1988, 3056)
        })
    }
>
....Stuff
</Formik>
 

Ответ №2:

Мне удалось сделать это с помощью этой функции

 function checkAspectRatio(value) {
  return new Promise(resolve => {
    const reader = new FileReader();
    reader.readAsDataURL(value);
    reader.onload = function(value) {
      const img = new Image();
      img.src = value.target.resu<
      img.onload = function() {
        const aspectRatio = this.width / this.height;
        resolve(aspectRatio);
      };
    };
  });
} 

используется Object.defineProperty() для определения нового свойства объекта

 Object.defineProperty(file, 'aspectRatio', {
  value: await checkAspectRatio(file)
}); 

и проверьте значение с помощью yup

 .test(
  'fileAspectRatio',
  'Please recheck the image resolution',
  value => value amp;amp; value.aspectRatio === 1.6
); 

Комментарии:

1. Большое спасибо за это. Это спасло меня.

2. Привет, как вы выполняете часть «Определение нового свойства для объекта»? Кажется, я не могу этого сделать, когда файл загружается с помощью onClick на входе с типом «file»

3. @alexr89 убедитесь, что объект, для которого нужно определить свойство, существует, а затем вы можете его изменить

Ответ №3:

 image: Yup.mixed()
  .required("Image is required.")
  .test(
    "aspectRatio",
    "Aspect ratio must be 16:9",
    value => {
      return new Promise(resolve => {
        const reader = new FileReader();
        reader.readAsDataURL(value[0]);
        reader.onload = function(value) {
          const img = new Image();
          img.src = value.target.resu<
          img.onload = function() {
            const aspectRatio = this.width / this.height;
            resolve(aspectRatio === (16 / 9));
          };
        };
      });
    }
  ),
 

Ответ №4:

Вот два альтернативных метода, которые быстрее, чем (де) кодирование в / из base64, и не требуют filereader

 function checkAspectRatio (file) {
    const img = new Image()
    img.src = URL.createObjectURL(file)
    return img.decode().then(() => {
        URL.revokeObjectURL(img.src)
        return img.width / img.height
    })
}

// not as cross compatible
function checkAspectRatio (file) {
    return createImageBitmap(file)
      .then(bitmap => bitmap.width / bitmap.height)
}