【问题标题】:Image compression in react-nativereact-native 中的图像压缩
【发布时间】:2020-06-19 08:08:03
【问题描述】:

我正在尝试使用mozjpeg 压缩图像,当我根据它工作正常的文档在 node.js 中实现它时。

const input = fs.readFileSync("in.ppm");
const out = mozjpeg.encode(input, { quality: 85 });

我需要在客户端做压缩,所以我尝试对 react-native 做同样的事情,因为 react-native 不包含 fs 等核心节点模块,我需要去第三方库react-native-fs 用于文件读取。

当我尝试在 react-native 中执行 mozjpeg.encode(input, { quality: 85 }); 时,它会抛出 Unrecognized input file format --- perhaps you need -targa

服务器端实现

const mozjpeg = require("mozjpeg-js");
const fs = require("fs");

const input = fs.readFileSync(filePath);
const out = mozjpeg.encode(input, { quality: 85 });
console.error(out.stderr);
fs.writeFileSync("out.jpg", out.data);

客户端实现

fs.readFile(image.path).then(data => {
    const out = mozjpeg.encode(data, { quality: 85 });
    console.log(out);
}

这是我尝试过的事情的清单

  • 尝试以十六进制、缓冲区、base64 和纯 URL 字符串形式提供输入。
  • 由于 Android URL 包含 file:// 作为前缀,我也尝试将其删除。

【问题讨论】:

  • 我使用github.com/bamlab/react-native-image-resizer 高质量压缩图像
  • 是的,我目前正在使用它,但我想迁移到 mozjpeg 以减小文件大小。
  • 这个问题几乎肯定是与编码有关(假设文件被正确读取)。因为mozjpeg 期望文件被二进制编码可能类似于Buffer.from(data, 'utf8') 因为readFilereact-native-fs 默认是utf8

标签: javascript android react-native image-compression mozjpeg


【解决方案1】:

其实我不知道mozjpeg,但我更喜欢在问题环境上使用纯JavaScript的方式来解决我的问题。

我猜你的想法落在了单向 bios 中,离开 NodeJS 解决方案,你在 react-native 环境中,所以使用 React Native Compress ImageReact Native Image Resizer

根据我的经验,我更喜欢使用第二个,React Native Image Resizer

安装后,如下使用:

ImageResizer.createResizedImage(
  imageUri,
  newWidth,
  newHeight,
  compressFormat,
  quality
)
  .then( resizedImageUri => {

    // the resizedImageUri is accessible here to use.

  }).catch( err => {

  // Catch any error here.

});

【讨论】:

  • 我已经在使用 React Native Image Resizer,我只想从它迁移到 mozjpeg。
  • 亲爱的@Badri,您为什么要从 awesome 和 update 库迁移到另一个不兼容且有很多问题的环境的库?
  • 好吧,我比较了两种压缩方式,对我来说,mozjpeg 似乎有更好的压缩技术,并且与 react-native-compression 相比,输出文件降低了 20%,这对我正在开发的东西很重要。
  • @Badri,我们有三个环境,RN、Node、Browser,在浏览器中,压缩器方法使用canvas和base64对图像进行计算并进行一些更改,例如调整大小、旋转或压缩。在 Node 环境中,mozjpeg 使用基于MozJPEGfscjpeg,在RN 中不存在,在RN 中需要使用Device Native 模块,iOS :objective-c and Android: JAVA,我知道你说mozjpeg在压缩方面更好,但它与RN环境无关。
  • 是的,我完全同意你的观点,RN 没有 fs,有一个用于 react-native-fs 的包,用于读取文件输出将是 base64/ascii 或 utf- 8.由于 MozJpeg 仅支持二进制缓冲区,我尝试转换显然不起作用,我的问题是我在转换为二进制缓冲区的过程中是否遗漏了一些东西。顺便说一句,我已经在使用你建议的两个库 react-native-crop-picker 来选择图像和 react-native-image-resizer 来调整大小,我做了最好的研究,因为我可能需要减少 10- 15% 的尺寸并获得最佳质量。
【解决方案2】:

另外,还有另一个很好的 React-Native image crop picker 库,其目的是抓取一些图像并裁剪它们,但它具有很好的压缩能力。也许这个库有一个很好的压缩算法,比如 mozjpeg

它可以打开相机、打开图库或使用恒定图像,甚至可以切换裁剪:

ImagePicker.openCamera({
  width: 300,
  height: 400,
  compressImageQuality: 0.2
}).then(image => {
  // do what you want
}).catch(e => {
  // handle error
});

好配置,它有很多调整选项。希望对你有帮助。

【讨论】:

  • 亲爱的@Badri,如果可能的话,请将您的项目的一个简单的小型重新制作发布到 GitHub 或 GitLab 中,然后我将其克隆。也许我可以帮助你。
  • 谢谢我尽快发布链接
【解决方案3】:

您可以在mozjpeg-js doc 中找到输入参数是:

类型化数组或数据缓冲区


fs.readFile 客户端(react-native-fs)的返回类型为Promise<string> 并返回内容。 (Doc)

但在服务器端 (fs),fs.readFileSync 返回缓冲区对象。 (Doc)


因此您可以使用此函数将字符串更改为类型化数组:

function str2ta(str) {
  var bufView = new Uint16Array(str.length*2); // 2 bytes for each char
  for (var i=0, strLen=str.length; i<strLen; i++) {
    bufView[i] = str.charCodeAt(i);
  }
  return bufView;
}

【讨论】:

  • 我在文档上看到了这一点,这就是为什么我提到我已经以十六进制、缓冲区、base64 和纯 URL 字符串形式给出了输入。顺便说一句,我用这个函数来转换函数 base64ToHex(str) { console.log(str) const raw = atob(str);让结果 = ''; for (let i = 0; i
  • 你为什么不测试typed array?您的 base64ToHex 函数返回字符串,但我的 str2ta 返回类型化数组 @Badri
  • 我尝试了类型化数组、unit8buffer、int8buffer,在尝试了所有这些之后,我只在这里发布了我的问题,很抱歉没有提到我尝试过的更清晰的输入,我尝试了你的函数也仍然抛出相同的错误。我尝试了来自节点的十六进制 bcoz fs 默认情况下返回十六进制缓冲区,因为它在我的服务器代码中工作我尝试将其作为最后的手段@Mohsen
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-08-09
  • 1970-01-01
  • 1970-01-01
  • 2020-02-29
  • 1970-01-01
相关资源
最近更新 更多