'Share JPEG file stored on S3 via URL instead of downloading

I have recently completed this tutorial from AWS on how to create a thumbnail generator using lambda and S3: https://docs.aws.amazon.com/lambda/latest/dg/with-s3-tutorial.html . Basically, I'm uploading an image file to my '-source' bucket and then lambda generates a thumbnail and uploads it to my '-thumbnail' bucket.

Everything works as expected. However, I wanted to use s3 object URL in the '-thumbnail' bucket so that I can load the image from there for a small app I'm building. The issue I'm having is that the URL doesn't display the image in the browser but instead downloads the file. This causes my app to error out.

I did some research and learned that I had to change the content-type to image/jpeg and then also made the object public using ACL. This works for all of the other buckets I have except the one that has the thumbnail. I have recreated this bucket several times. I even copied the settings from my existing buckets. I have compared settings to all the other buckets and they appear to be the same.

I wanted to reach out and see if anyone has ran into this type of issue before. Or if there is something I might be missing.

Here is the code I'm using to generate the thumbnail.

import boto3
from boto3.dynamodb.conditions import Key, Attr
import os
import sys
import uuid
import urllib.parse
from urllib.parse import unquote_plus
from PIL.Image import core as _imaging
import PIL.Image

s3 = boto3.client('s3')
dynamodb = boto3.resource('dynamodb')
table = dynamodb.Table(os.environ['DB_TABLE_NAME'])

def lambda_handler(event, context):
  
    bucket = event['Records'][0]['s3']['bucket']['name']
    key = urllib.parse.unquote_plus(event['Records'][0]['s3']['object']['key'], encoding='utf-8')
    recordId = key
    tmpkey = key.replace('/', '')
    download_path = '/tmp/{}{}'.format(uuid.uuid4(), tmpkey)
    upload_path = '/tmp/resized-{}'.format(tmpkey)
    
    try:
        s3.download_file(bucket, key, download_path)
        resize_image(download_path, upload_path)
        bucket = bucket.replace('source', 'thumbnail')
        s3.upload_file(upload_path, bucket, key)
        print(f"Thumbnail created and uploaded to {bucket} successfully.")
        
    except Exception as e:
        print(e)
        print('Error getting object {} from bucket {}. Make sure they exist and your bucket is in the same region as this function.'.format(key, bucket))
        raise e
    else:
        s3.put_object_acl(ACL='public-read', 
        Bucket=bucket, 
        Key=key)
      #create image url to add to dynamo
        url = f"https://postreader-thumbnail.s3.us-west-2.amazonaws.com/{key}"
        print(url)

        #create record id to update the appropriate record in the 'Posts' table
        recordId = key.replace('.jpeg', '')
        #add the image_url column along with the image url as the value
        table.update_item(
        Key={'id':recordId},
          UpdateExpression=
            "SET #statusAtt = :statusValue, #img_urlAtt = :img_urlValue",                   
          ExpressionAttributeValues=
            {':statusValue': 'UPDATED', ':img_urlValue': url},
        ExpressionAttributeNames=
          {'#statusAtt': 'status', '#img_urlAtt': 'img_url'},
    )



def resize_image(image_path, resized_path):
  with PIL.Image.open(image_path) as image:
      #change to standard/hard-coded size
      image.thumbnail(tuple(x / 2 for x in image.size))
      image.save(resized_path)




Solution 1:[1]

This could happen if the Content-Type of the file you're uploading is binary/octet-stream , you can modify your script like below to provide custom content-type while uploading.

s3.upload_file(upload_path, bucket, key, ExtraArgs={'ContentType': 
"image/jpeg"})

Solution 2:[2]

After more troubleshooting the issue was apparently related to the bucket's name. I created a new bucket with a different name than it had previously. After doing so I was able to upload and share images without issue.

I edited my code so that the lambda uploads to the new bucket name and I am able to share the image via URL without downloading.

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 DilLip_Chowdary
Solution 2