expo-image-manipulator 弄乱了图像的纵横比

expo-image-manipulator messes up aspect ratio of images

我们已经使用 Expo Image Manipulator 实现了图像压缩。我们面临的问题是,一些来自压缩功能的照片被弄乱了。示例:

https://i.stack.imgur.com/JezvB.png

图像在 iOS 设备上永远不会弄乱,它在 Android(12、11)上随机发生,主要是在三星手机上。

技术栈: EXPO SDK 43(托管工作流) 反应本机 0.64.3

我们用来处理压缩的代码:

cameraParsing = async (result) => {
  if (result.cancelled) {
    return
  }

  const { uri, width, height } = result

  const percentage = this.getResizePercentage(width, height)

  const croppedImage = await manipulateAsync(
    uri,
    [
      {
        resize: {
          width: width - width * percentage,
          height: height - height * percentage,
        },
      },
    ],
    {
      compress: 0.4,
    },
  )

  const fileName = uri.split('/')[uri.split('/').length - 1]

  this.setState({
    selectedFile: fileName,
    selectedUri: croppedImage.uri,
  })

  this.props.setFieldValue(this.props.field.key, {
    uri: croppedImage.uri,
    type: mime.lookup(fileName),
    name: fileName,
  })
}

getResizePercentage = (width, height) => {
  let percentage = 0
  let newWidth = width
  let newHeight = height

  while (newWidth > 1200 || newHeight > 1150) {
    percentage += 0.01
    newWidth = width - width * percentage
    newHeight = height - height * percentage
  }

  return percentage
}

也许有人遇到了这个问题并可以帮助解决这个问题?

当您强制图像的高度 + 宽度时会发生这种情况,如果图像是例如,如果您有横向图像但想要方形图像(100 宽 100 高),它会拉伸图像,然后它将以这种方式裁剪它。我建议只定义宽度,这样它就会有自动高度。

所以我已经设法解决了这个问题。

这个问题实际上与设备如何管理图像的纵横比有关。例如,iPhone 相机使用纵横比 4:3、16:9 等(其中 4 是高度,3 是宽度)。但是,某些 Android 设备使用不同的纵横比:3:4、9:16,其中 4 是高度,3 是宽度。这里的问题是 expo 相机总是处理 4:3 的图像,所以最后,图像尺寸数据是错误的。

假设我正在上传一张尺寸为 3024x4032 的照片。

iPhone returns:

{
  "cancelled": false,
  "height": 4032,
  "type": "image",
  "uri": "...",
  "width": 3024
}

Android returns:

{
  "cancelled": false,
  "height": 3024,
  "type": "image",
  "uri": "...",
  "width": 4032
}

如果你看得足够仔细,你会看到 Android 案例 returns 混合尺寸(高度作为宽度,宽度作为高度)。这会使压缩弄乱图像。

为了解决这个问题,我发现 React Native 的内置方法 Image.getSize 总是 returns 正确的尺寸,所以最终代码如下所示:

getResizePercentage = (width, height) => {
  let percentage = 0
  let newWidth = width
  let newHeight = height

  while (newWidth > 1200 || newHeight > 1150) {
    percentage += 0.01
    newWidth = width - width * percentage
    newHeight = height - height * percentage
  }

  return percentage
}

cameraParsing = async (result) => {
  if (result.cancelled) {
    return
  }

  this.setState({ compressionInProgress: true })

  const { uri } = result

  Image.getSize(result.uri, async (width, height) => {
    const percentage = this.getResizePercentage(width, height)

    const croppedImage = await manipulateAsync(
      uri,
      [
        {
          resize: {
            width: width - width * percentage,
            height: height - height * percentage,
          },
        },
      ],
      {
        compress: 0.5,
      },
    )

    this.setState({ compressionInProgress: false })

    const fileName = uri.split('/')[uri.split('/').length - 1]

    this.setState({
      selectedFile: fileName,
      selectedUri: croppedImage.uri,
    })

    this.props.setFieldValue(this.props.field.key, {
      uri: croppedImage.uri,
      type: mime.lookup(fileName),
      name: fileName,
    })
  })
}

另外,请问各位大神,我确实查了世博相机返回的EXIF数据,也是错误的。

我希望这对其他人有帮助。