如何让 HEIC 图像格式在 s3 中工作

发布于 2025-01-20 17:15:24 字数 759 浏览 6 评论 0原文

我正在处理在 AWS S3 存储桶中保存和显示图像。我使用的是 Mac,图像在 Mac 上显示良好。

我可以将许多图像上传到存储桶,然后可以使用预签名的 URL 显示它们。一切都很好...

但是我还有一些其他不同的图像,例如 .jpg,我在 mac 上看到的很好,并且似乎可以上传,但是不使用预签名 URL 从 s3 显示。当在 Mac Safari、chrome 或 Firefox 中查看时,我收到损坏的图像符号。 Firefox 还说:

图像“https://xxxxxxxxxx”无法显示,因为它包含错误”

有人建议,原始文件创建可能在某种程度上很奇怪,Mac 可能能够解释该图像,但 S3 无法做到这一点可能这可能是跨平台 Windows/Mac/Linux 图像问题?

测试:我拍摄了一张未从 S3 中显示的 .jpg 图像 - 我在 Mac 上以预览形式打开了它,并将其导出为 .然后使用不同的名称。我上传了这个新版本,这似乎解决了问题,因为它现在可以从 s3 正确显示,

但是对于我正在做的事情,我不想导出每个图像并重新保存它 - 为了转到 S3。

问:有人知道为什么我在尝试从 S3 显示图像时遇到一些错误吗?有什么想法可以解决这个问题吗?

- 可能的线索: - 在 Mac 终端中我尝试过:

 file -I ~/Desktop/test.jpg 

令人惊讶的是它返回为 = 图像/heic 即使文件有.jpg 后缀...知道如何让 s3 读取“heic 文件”或者只是让它工作吗?

谢谢戴夫

I'm working with saving and displaying images in an AWS S3 bucket. I am on a mac and the images show fine on the mac.

I am able to upload many images to the bucket and then I can display them using a pre-signed URL. All good...

But then I have some other varied images such as .jpg that I see fine on the mac and seem to upload OK however do not display from s3 using pre-signed URL. When viewed in Mac Safari or chrome or Firefox I get the broken image symbol. Firefox also says:

The image "https://xxxxxxxxxx" cannot be displayed because it contains errors"

Someone suggested that possibly the original file creation might have been strange in someway and the Mac might be able to interpret the image however S3 cannot do this successfully. Possibly this might be a cross platform Windows / Mac / Linux image issue?

Test: I took one of the .jpg images that did not show up from S3 - and I opened it in preview on the Mac and exported it also as .jpg under a different name. Then I uploaded this new Version add this did seem to fix the problem because it now she displays correctly from s3.

However for what I'm doing I do not want to have to export every image and resave it - in order to go to S3.

Q: Does anybody have any solutions as to why I am getting some Errors when trying to display images from S3? Any ideas how to fix this?

-- possible clue : - in Mac terminal I tried :

 file -I ~/Desktop/test.jpg 

and surprisingly it came back as = image/heic even though the file had .jpg suffix.... Any idea how to get s3 to read "heic files" or just get this working?

Thanks Dave

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

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

发布评论

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

评论(1

書生途 2025-01-27 17:15:25

我也遇到了这个问题。对我来说,当iCloud在iCloud共享文件和iPad或MacOS设备之间的文件时,正在执行一些自动“转换”带来的问题。转换为JPG的转换通常只是将文件扩展名重命名为.jpg而不将文件更改为JPG。非常令人困惑和令人沮丧,对苹果的品牌不是很混乱。

在打击这个“假JPG”问题时,您应该知道一些细微差别。

首先是您需要能够分辨出您的HEIC文件是否具有错误的扩展名。要确定文件的实际类型,您可以使用文件的实际数据而不是扩展名。文件的前几个字节包含文件类型(又称文件的“魔术号”)。

您可以创建一个lambda功能,该功能检查每个已知的魔术号码,但是让Node.js软件包为您处理它要容易得多。我在此代码中使用了file-type-ext npm软件包,我在AWS lambda上托管了该软件包。我将HTTP请求发送给API网关,并使用我要检查的文件的存储键名和键,然后返回实际的文件扩展名(或错误)。

const AWS = require('aws-sdk');
const fileType = require('file-type-ext');

exports.handler = async (event) => {
  const s3 = new AWS.S3();

  // Retrieve the bucket and key from the event
  console.log('event.body:');
  console.log(event.body);
  let payload = JSON.parse(event.body);
  const bucket = payload.bucket; console.log('bucket: ' + bucket );
  const key = payload.key; console.log('key: ' + key );

  try {
    // Retrieve the file from S3
    const params = {
      Bucket: bucket,
      Key: key
    };

    const { Body } = await s3.getObject(params).promise();

    // Determine the file extension based on the magic number
    const fileBuffer = Buffer.from(Body);
    const { ext } = fileType(fileBuffer);

    if (ext) {
      return {
        statusCode: 200,
        body: ext
      };
    } else {
      return {
        statusCode: 500,
        body: 'File extension not found'
      };
    }
  } catch (error) {
    return {
      statusCode: 500,
      body: error.message
    };
  }
};

一旦知道文件的实际类型,我的建议是使用单独的lambda函数将文件转换为JPG。这将使任何现代浏览器都可以阅读。我的问题完全是Heics伪装成JPG,因此我只需要一个功能来应对HEIC转换。我尝试了几个不同的node.js软件包,并最终使用了HEIC-Convert。这是我最终得到的lambda功能。它摄取了一个命名较差的HEIC文件,将其转换为JPG,然后将其保存为随机命名的JPG,并将其保存在同一桶中。

const { promisify } = require('util');
const fs = require('fs');
const convert = require('heic-convert');
const axios = require('axios');
const AWS = require('aws-sdk');
var payload = {};
var fileURL;
const BUCKET = process.env.BUCKET;

const s3 = new AWS.S3();

exports.handler = async (event, context) => {
  
  console.log('Event recieved.');
  console.log(event.body);
  payload = JSON.parse(event.body);
  fileURL = payload.URL;
  console.log('fileURL: ' + fileURL );
  
  try {
    const response = await axios.get(fileURL, {
      responseType: 'arraybuffer',
    });
    console.log('File downloaded successfully.', response.data);

    const inputBuffer = Buffer.from(response.data, 'binary');

    const outputBuffer = await convert({
      buffer: inputBuffer,
      format: 'JPEG',
      quality: 1,
    });
    console.log('File converted successfully.', outputBuffer);

    let rando = generateRandomString(16);

    const s3Params = {
      Bucket: BUCKET,
      Key: rando + '.jpg',
      Body: outputBuffer,
      ACL: 'public-read',
      ContentType: 'image/jpg'
    };

    const uploadResult = await s3.upload(s3Params).promise();
    console.log('File uploaded successfully:', uploadResult.Location);

    return {
      statusCode: 200,
      body: JSON.stringify({message: 'Conversion and upload completed successfully.', jpgLocation:  uploadResult.Location})
    };
  } catch (error) {
    console.error('Error converting HEIC to JPG:', error);
    return {
      statusCode: 500,
      body: 'An error occurred during conversion and upload.',
    };
  }
};


function generateRandomString(length) {
  let result = '';
  const characters = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';
  
  for (let i = 0; i < length; i++) {
    const randomIndex = Math.floor(Math.random() * characters.length);
    result += characters.charAt(randomIndex);
  }

  return result;
}

当您设置Lambda功能时,请不要忘记,您必须给他们IAM权限才能读/编写相关的S3存储桶。您还需要调整功能的可用执行时间和内存津贴,并为任何敏感数据(例如您的存储键名)设置环境变量。

I ran into this issue too. For me, there was some issues that were brought on by an automatic "conversion" to jpg that was being performed when a file was shared via iCloud between an iPhone and an iPad or MacOS device. The conversion to jpg often just renamed the file extension to .jpg without changing the file to a jpg. Very confusing and frustrating, and not very on brand for Apple.

There's a few nuances that you should be aware of when combating this "fake jpg" issue.

The first is that you need to be able to tell if you have HEIC files with the wrong extension. To determine the actual type of the file, you can use the file's actual data instead of the extension. The first few bytes of the file contain the file type (aka the file's "magic number").

You could create a Lambda function that checks for every known magic number but it's a lot easier to let an node.js package handle that for you. I used the file-type-ext NPM package in this code, which I hosted on AWS Lambda. I send an HTTP request to the API gateway with the bucket name and key of the file I want to check, and it returns the actual file extension (or an error).

const AWS = require('aws-sdk');
const fileType = require('file-type-ext');

exports.handler = async (event) => {
  const s3 = new AWS.S3();

  // Retrieve the bucket and key from the event
  console.log('event.body:');
  console.log(event.body);
  let payload = JSON.parse(event.body);
  const bucket = payload.bucket; console.log('bucket: ' + bucket );
  const key = payload.key; console.log('key: ' + key );

  try {
    // Retrieve the file from S3
    const params = {
      Bucket: bucket,
      Key: key
    };

    const { Body } = await s3.getObject(params).promise();

    // Determine the file extension based on the magic number
    const fileBuffer = Buffer.from(Body);
    const { ext } = fileType(fileBuffer);

    if (ext) {
      return {
        statusCode: 200,
        body: ext
      };
    } else {
      return {
        statusCode: 500,
        body: 'File extension not found'
      };
    }
  } catch (error) {
    return {
      statusCode: 500,
      body: error.message
    };
  }
};

Once you know the file's actual type, my recommendation would be to use a separate Lambda function to convert the file to jpg. This would make it readable by any modern browser. My issue was entirely with HEICs masquerading as jpgs, so I only needed a function to deal with HEIC conversions. I tried a few different node.js packages and eventually went with heic-convert. Here's the Lambda function I ended up with. It ingests the a poorly named HEIC file, converts it to a JPG, then saves it as a randomly named jpg in the same bucket.

const { promisify } = require('util');
const fs = require('fs');
const convert = require('heic-convert');
const axios = require('axios');
const AWS = require('aws-sdk');
var payload = {};
var fileURL;
const BUCKET = process.env.BUCKET;

const s3 = new AWS.S3();

exports.handler = async (event, context) => {
  
  console.log('Event recieved.');
  console.log(event.body);
  payload = JSON.parse(event.body);
  fileURL = payload.URL;
  console.log('fileURL: ' + fileURL );
  
  try {
    const response = await axios.get(fileURL, {
      responseType: 'arraybuffer',
    });
    console.log('File downloaded successfully.', response.data);

    const inputBuffer = Buffer.from(response.data, 'binary');

    const outputBuffer = await convert({
      buffer: inputBuffer,
      format: 'JPEG',
      quality: 1,
    });
    console.log('File converted successfully.', outputBuffer);

    let rando = generateRandomString(16);

    const s3Params = {
      Bucket: BUCKET,
      Key: rando + '.jpg',
      Body: outputBuffer,
      ACL: 'public-read',
      ContentType: 'image/jpg'
    };

    const uploadResult = await s3.upload(s3Params).promise();
    console.log('File uploaded successfully:', uploadResult.Location);

    return {
      statusCode: 200,
      body: JSON.stringify({message: 'Conversion and upload completed successfully.', jpgLocation:  uploadResult.Location})
    };
  } catch (error) {
    console.error('Error converting HEIC to JPG:', error);
    return {
      statusCode: 500,
      body: 'An error occurred during conversion and upload.',
    };
  }
};


function generateRandomString(length) {
  let result = '';
  const characters = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';
  
  for (let i = 0; i < length; i++) {
    const randomIndex = Math.floor(Math.random() * characters.length);
    result += characters.charAt(randomIndex);
  }

  return result;
}

When you set up your Lambda functions, don't forget that you'll have to give them IAM permissions to read/write the relevant S3 buckets. You'll also need to adjust the amount of available execution time and memory allowances for the functions, as well as setting up enviornment variables for any sensitive data, like your bucket names.

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