Easily create wallpapers for any device with Transloadit
Choosing a new wallpaper for your devices is always a tough endeavor. Yet, there's nothing worse than stumbling upon the perfect wallpaper and finding it doesn't quite fit. If this has happened to you, we're here to help! Take a look at how you can use the power of Transloadit to resize any wallpaper and make it fit perfectly on any device.

Template
As (part of) the saying goes: "Teach a man to fish, and you feed him for a lifetime." Therefore, we will be teaching you how to make a website that automatically resizes any wallpaper to fit any screen size 🎣
The first step in making our website is creating a Transloadit Template. A
Template is a series of Assembly Instructions that Transloadit will later use
to resize our wallpaper to the correct dimensions, using the fillcrop
resize strategy. Below is the
Template that we'll be using today.
{
"steps": {
":original": {
"robot": "/upload/handle"
},
"crop_thumbed": {
"use": ":original",
"robot": "/image/resize",
"height": "${fields.height}",
"width": "${fields.width}",
"imagemagick_stack": "v3",
"resize_strategy": "fillcrop"
},
"exported": {
"use": ["crop_thumbed"],
"robot": "/s3/store",
"credentials": "S3_CREDENTIALS",
"result": true
}
}
}
You might notice that we are using ${fields.height} and ${fields.width}. These are fields that
can be dynamically passed into a Template, so that we can adjust the behavior at runtime.
More generically speaking, these are Assembly Variables, and there's a variety of them
that you can use in your Assemblies. Learn more about the different uses of Assembly
Variables here.
Before deploying publicly, use server-generated signatures and validate
the requested dimensions on your server. Keep your Auth Secret out of browser code. The browser
example below demonstrates the upload and preview behavior using your own Template and Auth Key.
Replace S3_CREDENTIALS with the name of your saved
Template Credentials; do not paste S3 secrets into the example.
HTML & CSS
We are not going to take as deep a dive into the HTML and CSS as we usually do, but feel free to take a look at both below, in case you'd like to copy-paste them into your own project.
<head>
<link href="https://releases.transloadit.com/uppy/v3.7.0/uppy.min.css" rel="stylesheet" />
</head>
<div class="content">
<h1>Wallpaper Resizer</h1>
<div class="button-list" id="preview-buttons"></div>
<label>Choose a photo <input id="photo-input" type="file" accept="image/*" /></label>
<p>You can also drop a photo over the frame</p>
<div id="preview-box"><img id="preview-image" alt="Resized wallpaper preview" hidden /></div>
<div id="progress-bar"></div>
<div class="button-list">
<a id="download" hidden>View wallpaper</a>
<button id="clear">Clear</button>
</div>
</div>
#preview-box {
border: 1px solid black;
border-radius: 10px;
display: flex;
align-items: center;
justify-content: center;
width: 384px;
max-width: 100%;
aspect-ratio: 16 / 9;
overflow: clip;
position: relative;
}
#preview-image {
position: absolute;
inset: 0;
height: 100%;
width: 100%;
object-fit: cover;
}
.content {
display: flex;
flex-direction: column;
align-items: center;
gap: 10px;
font-family: Helvetica;
}
.button-list {
display: flex;
flex-wrap: wrap;
justify-content: center;
gap: 10px;
}
JavaScript
Now we can take a look at my favorite part of each blog – the integration code.
Place this script after the HTML inside a <script type="module"> tag. Replace the Auth Key and
Template ID placeholders with your own values.
import {
Uppy,
DropTarget,
Informer,
ProgressBar,
Transloadit,
} from 'https://releases.transloadit.com/uppy/v3.7.0/uppy.min.mjs'
const uppy = new Uppy({
restrictions: {
allowedFileTypes: ['image/*'],
maxNumberOfFiles: 1,
},
autoProceed: true,
})
.use(DropTarget, {
target: '#preview-box',
})
.use(Informer, {
target: 'body',
})
.use(ProgressBar, {
target: '#progress-bar',
fixed: true,
})
.use(Transloadit, {
waitForEncoding: true,
assemblyOptions: () => ({
params: {
auth: { key: 'YOUR_AUTH_KEY' },
template_id: 'YOUR_TEMPLATE_ID',
},
fields: { height: cropHeight, width: cropWidth },
}),
})
.on('transloadit:complete', setPreviewImage)
const previewBox = document.getElementById('preview-box')
const previewImage = document.getElementById('preview-image')
let cropHeight = 1080
let cropWidth = 1920
const resolutions = [
[1920, 1080],
[1080, 1920],
[2560, 1080],
[1080, 2560],
[1366, 768],
[768, 1366],
]
const previewScale = 0.2
resolutions.forEach(appendButton)
document.getElementById('clear').addEventListener('click', clearPreview)
document.getElementById('photo-input').addEventListener('change', (event) => {
const file = event.currentTarget.files[0]
if (file == null) return
clearPreview()
try {
uppy.addFile({ name: file.name, type: file.type, data: file })
} catch {
uppy.info('Choose one image file and try again.', 'error', 5000)
}
event.currentTarget.value = ''
})
function setPreviewImage(assembly) {
const url = assembly.results.exported?.[0]?.ssl_url
if (typeof url !== 'string') {
uppy.info('No wallpaper was returned. Please try again.', 'error', 5000)
return
}
previewImage.hidden = false
previewImage.src = url
const downloadButton = document.getElementById('download')
downloadButton.href = url
for (const file of uppy.getFiles()) uppy.removeFile(file.id)
downloadButton.hidden = false
}
function clearPreview() {
previewImage.hidden = true
previewImage.removeAttribute('src')
const downloadButton = document.getElementById('download')
downloadButton.hidden = true
downloadButton.removeAttribute('href')
for (const file of uppy.getFiles()) uppy.removeFile(file.id)
}
function appendButton(resolution) {
const buttonTextEl = document.createElement('button')
buttonTextEl.className = 'button'
buttonTextEl.innerText = `${resolution[0]}x${resolution[1]}`
buttonTextEl.setAttribute('data-width', resolution[0])
buttonTextEl.setAttribute('data-height', resolution[1])
buttonTextEl.addEventListener('click', setPreviewBoxDimensions)
document.getElementById('preview-buttons').appendChild(buttonTextEl)
}
function setPreviewBoxDimensions(e) {
cropHeight = Number(e.currentTarget.getAttribute('data-height'))
cropWidth = Number(e.currentTarget.getAttribute('data-width'))
previewBox.style.width = `${cropWidth * previewScale}px`
previewBox.style.aspectRatio = `${cropWidth} / ${cropHeight}`
clearPreview()
}
Let's comb through the code line by line.
Since we are making a website, we naturally start by importing the best file uploader in the world,
Uppy. We first need to create a new instance of Uppy, and then initialize all of
our plugins. For today's demo, we will be using the:
Drop target plugin,
Informer plugin,
Progress bar plugin and finally, the
Transloadit plugin. Importantly, we set autoProceed to
true, so that our file is uploaded to Transloadit as soon as we drop an image over the preview.
After this, we declare a few variables and constants to be used in our functions later on, as well
as an array of resolutions. We can later call the appendButton function for each resolution to
create a button corresponding to each screen size we want to target.
Functions
Let's now move on to each of the functions we reference.
The setPreviewImage function is called from the transloadit:complete event from Uppy – which is
called whenever the Transloadit Assembly is finished. We then inspect the Assembly
JSON from our result and retrieve the ssl_url of the file from our S3 bucket. We can then
set the preview image's visibility, and assign it the correct image.
Since we are setting a preview image, we're going to want to clear it too! That's where the suitably
named clearPreview comes in. This function completes two very basic tasks: it hides the preview
image element and removes any pending file from Uppy. Once a result is shown, setPreviewImage
releases the completed file too, so another photo can be dropped without first pressing Clear.
The Transloadit plugin is installed once. Its assemblyOptions function reads the selected integer
dimensions at the start of each upload and sends them as fields alongside the parameters. Changing
the resolution therefore does not reinstall the plugin or derive pixel counts from scaled preview
dimensions. The file input also supports choosing a photo without drag and drop.
Next up is appendButton! The functionality here is pretty self-explanatory. We create a button
element, using one of the resolution pairs. Notably, we add two data attributes, data-width and
data-height, just to make it a little easier for us later on to retrieve these values from the
button.
Last but not least is setPreviewBoxDimensions. Here, we retrieve the data attributes that were
previously mentioned, and use these to resize our preview box to the same aspect ratio, only scaled
down a little to fit the page.
Final results
Combine the HTML, CSS and module script, configure your Template, and serve the page locally.
Pick a resolution, choose or drop a photo, and open the resulting wallpaper to save it from your browser. The resized image fits the selected device, ranging from a Samsung Galaxy smartphone to an ultrawide desktop monitor.
And with that, we've reached the end of today's blog! If you are eagerly waiting for the next blog, be sure to sign up for the newsletter in order to receive updates on the latest Transloadit developments, as well as tech articles that we find interesting.
