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

发布于 2025-01-20 03:24:04 字数 1397 浏览 2 评论 0原文

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

https://i.sstatic.net/jezvb.png

在iOS设备上,它在Android上随机发生(12,11),主要是在三星手机上。

技术堆栈: Expo SDK 43(托管工作流) React Native 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
}

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

we've implemented image compression using Expo Image Manipulator. The problem, that we are facing, is that some photos that comes from the compression functionality are messed up. Example:

https://i.sstatic.net/JezvB.png

The images are never messed up on iOS devices, it happens randomly on Android (12, 11), mostly on Samsung phones.

Tech stack:
EXPO SDK 43 (Managed workflow)
React Native 0.64.3

The code which we are using to handle compression:

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
}

Maybe someone had this issue and could help resolve this?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

暮凉 2025-01-27 03:24:04

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

this happens when you force a height + width to the image, it will stretch the image if the image is for example if you have a landscape image but want to have a square image (100 width 100 height) then it will crop it that way. I would suggest to only define width, that way it will have auto height.

薔薇婲 2025-01-27 03:24:04

因此,我设法解决了这个问题。

该问题实际上与设备如何管理图像的长宽比有关。例如,iPhone摄像头使用纵横比4:3、16:9等(其中4是高度,3是宽度)。但是,某些Android设备使用不同的纵横比:3:4,9:16其中4是高度,3是宽度。这里的问题是,如果图像为4:3,则始终处理图像,因此最终,图像尺寸数据是错误的。

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

iPhone返回:

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

Android返回:

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

如果您看起来足够近,您会看到,Android Case返回混合尺寸(高度为宽度,宽度为高度)。这使压缩搞砸了图像。

为了解决这个问题,我发现React Native在方法image中的内置。GetSize始终返回正确的尺寸,因此最终代码看起来像这样:

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数据博览会摄像头,这也是错误的。

我希望这对别人有帮助。

So I've managed to resolve the issue.

The issue is actually related to how the device manages image's aspect ratio. For example, iPhone camera uses aspect ratios 4:3, 16:9, etc (where 4 is height and 3 is width). However, some Android devices uses different aspect ratios: 3:4, 9:16 where 4 is height and 3 is width. The issue here is that expo camera always handles the images if they are 4:3, so in the end, image dimensions data are wrong.

Let's say I'm uploading a photo with the size of 3024x4032.

iPhone returns:

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

Android returns:

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

If you look close enough, you will see, that Android case returns mixed dimensions (height is put as width, and width as height). This makes compression mess up the image.

To resolve this, I've found that react native's built in method Image.getSize always returns the correct dimensions, so the final code looks like this:

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,
    })
  })
}

Also, to whom it may concern, I did check the EXIF data returned by the expo camera, and it was wrong too.

I hope this helps to someone else.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文