How to Generate Animated Movie Poster Designs Using AWS Lambda & Stable Diffusion (via AWS Bedrock)

Table of contents
- 🛡️ Setting Up IAM Roles and Permissions
- 🧪Test & Deploy your Lambda function.
- How Create a New REST API
- Step 2: Create a Resource
- Step 3: Create a Method
- Step 4: Under GET, go to Method request
- Step 5: Under GET, go to Integration request
- Step 6: Deploy the API to a Stage(Dev or any other)
- 7: Go to Resources
- Test out using POSTMAN
- 📈 Scaling and Optimizing for Production
- 4. Deploy the Step Function via AWS Console
- API Gateway → Step Function Integration
- 🔍 5. Testing the Step Function
- Docker Build
- AWS Clients
Introduction:
Creating movie posters has always been an art form, but what if you could design one using just a text prompt? Imagine typing in something like "cyberpunk city with neon lights and a mysterious hero" and instantly getting a vivid movie poster. That’s what we’re doing here — and no, you don’t need to be an AI expert.
🌐 Tools & Services You’ll Need :
AWS Lambda : Runs code without managing servers.
Amazon Bedrock: Access foundation models (like Stable Diffusion) without training or infrastructure headaches.
Stability AI's Stable Diffusion Text-to-image generator.
Amazon S3: Stores your generated images.
IAM Roles Controls : who can do what.
Boto3 (Python SDK) : interacts with AWS services.
🚀 Step-by-Step Guide:
1. Set Up Your AWS Account :
If you haven’t already, sign up for an AWS account.
Enable Bedrock and make sure your account is in a region that supports Bedrock (e.g. us-east-1 or us-west-2).
2 .Create an S3 Bucket .
Head over to the S3 console, click "Create Bucket "
and give it a unique and easy to remember name like: animated-poster-generator-bucket .
Keep all default settings for s3 bucket, but make sure Block Public Access checkbox is ON
(we’ll use pre-signed URLs instead).
3 . Enable AWS Bedrock & Grant Access to Stability AI
Go to AWS Bedrock in the console.
Choose Stability AI as your provider.
Click “Enable Access” to the Stable Diffusion model.
Step 4. Write the Lambda Function . We will use Python3 to create Lambda function that accepts a prompt then sends it to the Stable Diffusion model via Bedrock.
Saves the image to S3 and Returns a pre-signed URL.
We'll use an event input that looks like this:
{ "prompt": "A fantasy movie poster featuring a dragon and a warrior" }
Calling the Stable Diffusion Model Here’s the magic:
import boto3
import base64
bedrock = boto3.client('bedrock-runtime')
def call_model(prompt): response
= bedrock.invoke_model( modelId="stability.stable-diffusion-xl-v1",
body=json.dumps({"text_prompts": [{"text": prompt}]}),
contentType="application/json", accept="application/json" )
result = json.loads(response['body'].read())
image_bytes = base64.b64decode(result['artifacts'][0]['base64'])
return image_bytes
import uuid
def save_image_to_s3(image_bytes): s3 = boto3.client('s3')
filename = f"{uuid.uuid4()}.png"
bucket = "animated-poster-generator-bucket"
s3.put_object(Bucket=bucket, Key=filename,
Body=image_bytes, ContentType='image/ png')
return filename
# Generating the Pre-signed URL
def get_presigned_url(filename):
s3 = boto3.client('s3')
return s3.generate_presigned_url('get_object',
Params={'Bucket': 'animated-poster-generator-bucket', 'Key': filename},
ExpiresIn=3600)
🛡️ Setting Up IAM Roles and Permissions
Create a Lambda execution role with the following permissions:
You can select from custom dropdown the access you want to give:
AmazonS3FullAccess or PutObject and GetObject access
Amazon Bedrock Invoke ModelAccess
Attach this execution role when you create your Lambda function.
🧪Test & Deploy your Lambda function.
Invoke it via the AWS Console or an API Gateway trigger.
Pass your movie poster prompt.
Copy the returned pre-signed URL into your browser.
How Create a New REST API
Go to API Gateway in the AWS Management Console.
Click on Create API.
Select REST API, and then click Build.
Set the API name as .
Choose Edge-optimized for the Endpoint Type (for global users).
Click Create API.
Step 2: Create a Resource
Name your resource and create it
Step 3: Create a Method
Select the newly created resource.
Under Create Method, and choose GET
Choose integration type as Lambda and choose your existing lambda function and create method
Step 4: Under GET, go to Method request
Click Edit and under URL query string parameters,
add 'prompt' parameter and make it required
Change Request Validator to 'Validate query string parameters and headers'(so that when REST API is invoked, it has this query string parameter called 'prompt')
Click Save
Step 5: Under GET, go to Integration request
Click Edit and go to Mapping templates and add mapping templates as
'application/ json' body{"prompt" : "$input.params(‘prompt’)}
Step 6: Deploy the API to a Stage(Dev or any other)
Click 'Deploy API' on the top right corner
Under New stage, add a stage name called
7: Go to Resources
Go to Test module on the bottom right screen
Under Query Strings Field, provide "prompt=image of a unicorn"
Click Test
If all goes well, you will get a status code 200 and the presigned URL of the generated image
Download and view it using MS paint
Test out using POSTMAN
Under GET Method, you need to add the invoke URL
You can get the invoke URL by navigating to Stages on the left side and clicking on GET method hierarchially
Provide the key as prompt and under value add your unique prompt, like "unicorn with rainbows in dr.Seuss style"
Click 'Send'
If all goes well, you will get a status code 200 and the presigned URL of the generated image
Download and view it using MS paint
📦 Full Lambda Function :
import json
import boto3
import base64
import uuid
s3 = boto3.client('s3')
bedrock = boto3.client('bedrock-runtime')
BUCKET_NAME = 'animated-poster-generator-bucket'
def lambda_handler(event, context): prompt = event.get("prompt", "An epic fantasy movie poster")
# Call Stable Diffusion model
response = bedrock.invoke_model( modelId="stability.stable-diffusion-xl-v1",
body=json.dumps({"text_prompts": [{"text": prompt}]}),
contentType="application/json",
accept="application/json" )
result = json.loads(response['body'].read())
image_bytes = base64.b64decode(result['artifacts'][0]['base64'])
# Save to S3
file_name = f"{uuid.uuid4()}.png"
s3.put_object(Bucket=BUCKET_NAME, Key=file_name, Body=image_bytes, ContentType='image/png')
# Generate URL presigned_url = s3.generate_presigned_url( 'get_object', Params={'Bucket': BUCKET_NAME, 'Key': file_name}, ExpiresIn=3600 )
return { 'statusCode': 200, 'body': json.dumps({'url': presigned_url}) }
🔧 Troubleshooting Common Issues:
AccessDenied : Make sure IAM roles include access to Bedrock and S3.
Model Not Found: Ensure you’ve enabled Stable Diffusion from the Bedrock console.
❌ URL Expired Pre-signed URLs are time-limited. Default is 1 hour (3600 seconds).
📈 Scaling and Optimizing for Production
Cache Repeated Prompts: Save time and money.
Throttle Usage: Avoid going over free tier limits.
For chaining more complex logic like adding titles or filters- use Step Functions:
{
"Comment": "Generate AI Movie Poster and return pre-signed URL",
"StartAt": "GeneratePoster",
"States": {
"GeneratePoster": {
"Type": "Task",
"Resource": "arn:aws:lambda:us-east-1:123456789012:function:generateMoviePoster",
"InputPath": "$",
"OutputPath": "$.Payload",
"End": true
}
}
}
4. Deploy the Step Function via AWS Console
Go to AWS Step Functions > State Machines.
Click Create state machine.
Choose:
Author with code snippets
Standard workflow type
Paste in the JSON definition above.
Click Next.
Under IAM Role, let it create a new role automatically or use an existing role that allows
lambda:InvokeFunction
.API Gateway → Step Function Integration
You can also use API Gateway to trigger the Step Function directly (instead of triggering Lambda).
Use API Gateway REST API or HTTP API.
Use AWS Service Proxy integration.
Pass the input JSON directly to the Step Function and return the result to the client.
🔍 5. Testing the Step Function
Once created:
Click Start execution.
Paste your prompt JSON:
"prompt": "A fantasy poster of a knight riding a flaming dragon"
}
Run it.
Wait a few seconds.
The output will include the pre-signed URL like this:
{
"url": "https://animated-poster-generator-bucket.s3.amazonaws.com/abc123.png?..."
}
Click to open it in your browser 🎨
Docker Build
Now comes deploying part .
We will use Docker container to build and run our app.
# Use official Python image
FROM python:3.11-slim
# Set environment variables
ENV PYTHONDONTWRITEBYTECODE=1
ENV PYTHONUNBUFFERED=1
# Set working directory
WORKDIR /app
# Copy requirements file first to leverage Docker caching
COPY requirements.txt .
# Install dependencies
RUN pip install --no-cache-dir -r requirements.txt
# Copy app code
COPY . .
# Expose port 5000
EXPOSE 5000
# Run the Flask app
CMD ["python", "app.py"]
Flask API Wrapper:
Here's an example app.py to go with your containerized setup:
from flask import Flask, request, jsonify
import boto3
import base64
import uuid
import json
app = Flask(__name__)
# AWS Clients
s3 = boto3.client('s3')
bedrock = boto3.client('bedrock-runtime')
BUCKET_NAME = 'animated-poster-generator-bucket'
@app.route('/generate', methods=['GET'])
def generate_poster():
prompt = request.args.get('prompt', 'An epic fantasy movie poster')
try:
# Call Bedrock (Stable Diffusion)
response = bedrock.invoke_model(
modelId="stability.stable-diffusion-xl-v1",
body=json.dumps({"text_prompts": [{"text": prompt}]}),
contentType="application/json",
accept="application/json"
)
result = json.loads(response['body'].read())
image_bytes = base64.b64decode(result['artifacts'][0]['base64'])
# Upload to S3
file_name = f"{uuid.uuid4()}.png"
s3.put_object(Bucket=BUCKET_NAME, Key=file_name, Body=image_bytes, ContentType='image/png')
# Generate pre-signed URL
presigned_url = s3.generate_presigned_url(
'get_object',
Params={'Bucket': BUCKET_NAME, 'Key': file_name},
ExpiresIn=3600
)
return jsonify({'url': presigned_url})
except Exception as e:
return jsonify({'error': str(e)}), 500
if __name__ == '__main__':
app.run(debug=True, host='0.0.0.0')
AWS Clients
Now our remaining function which contains our Logic and aws clients:
s3 = boto3.client('s3')
bedrock = boto3.client('bedrock-runtime')
BUCKET_NAME = 'animated-poster-generator-bucket'
@app.route('/generate', methods=['GET'])
def generate_poster():
prompt = request.args.get('prompt', 'An epic fantasy movie poster')
try: # Call Bedrock (Stable Diffusion)
response = bedrock.invoke_model(
modelId="stability.stable-diffusion-xl-v1",
body=json.dumps({"text_prompts": [{"text": prompt}]}),
contentType="application/json", accept="application/json" )
result = json.loads(response['body'].read())
image_bytes = base64.b64decode(result['artifacts'][0]['base64'])
# Upload to S3
file_name = f"{uuid.uuid4()}.png"
s3.put_object(Bucket=BUCKET_NAME, Key=file_name, Body=image_bytes, ContentType='image/png')
# Generate pre-signed URL
presigned_url = s3.generate_presigned_url( 'get_object',
Params={'Bucket': BUCKET_NAME, 'Key': file_name}, ExpiresIn=3600 )
return jsonify({'url': presigned_url})
except Exception as e:
return jsonify({'error': str(e)}), 500
if name == 'main':
app.run(debug=True, host='0.0.0.0')
Build the Docker Image.
Make sure your Dockerfile, app.py, and requirements.txt are in the same directory.
docker build -t movie-poster-generator docker run -p 5000:5000 movie-poster-generator curl "http://localhost:5000/generate?prompt=epic+robot+warrior+poster"
Environment variables
AWS credentials volume mount
IAM roles for Amazon ECS or EC2 if deployed in AWS
Set the following environment variables when running the container :
export AWS_ACCESS_KEY_ID=your_key
export AWS_SECRET_ACCESS_KEY=your_secret
export AWS_DEFAULT_REGION=us-east-1
docker run -e
AWS_ACCESS_KEY_ID=your_key-e
AWS_SECRET_ACCESS_KEY=your_secret-e
AWS_DEFAULT_REGION=us-east-1
-p 5000:5000
Congratulations! You have built a text-to-poster generator using AWS Lambda and Stable Diffusion through Bedrock.
With just a prompt, you can now spin up unique, movie posters and store them in the cloud with shareable links. The whole process is serverless, scalable, and, honestly, kind of magical.
❓ FAQs
1. Can I make the API use POST instead of GET?
Yes! Just follow the same steps but select POST instead of GET, and pass the prompt in the request body.
2. How do I make the image more cinematic or stylized?
Use more descriptive prompts like “4K ultra-detailed, cinematic lighting, wide angle” to improve the image quality.
3. Can I generate multiple images at once?
Yes, you can tweak your Lambda to generate more than one image and return an array of URLs.
4. How much does this cost?
With moderate use, most parts (except Bedrock) fall under AWS Free Tier. Bedrock usage is pay-as-you-go based on model inference time.
5. Can I embed this in a website or app?
Absolutely! Use the generated pre-signed URL directly in your <img>
tags or fetch them via your app’s frontend.
The source code can be found in my github repo: https://github.com/lastoyster/Bedrock-Image-Generator
Clone it, Fork it, modify it .
Contributions are welcome.
Subscribe to my newsletter
Read articles from Pratiksha kadam directly inside your inbox. Subscribe to the newsletter, and don't miss out.
Written by
