The Image Upscaling API Is Now Included on Start, Grow and Scale

Posted on | Last updated on
The Image Upscaling API Is Now Included on Start, Grow and Scale

OCR, Envelope OCR, Document Detection, Image Enhancement and Image Upscaling used to be separate plugins. All five now run on Start, Grow and Scale, and the included allowances and overage rates are the same as they were.

This is the fifth of six posts on the Start, Grow and Scale processing tasks, one per task.

Image Upscaling is the one that doubles the width and height of an image on the way out, as a path segment in front of a handle.

A 600x400 fjord photograph beside the same file delivered through upscale at 1200x800, each with its metadata response, above the same patch of both shown at equal size
A 600×400 fjord photograph beside the same file delivered through upscale at 1200×800, each with its metadata response, above the same patch of both shown at equal size

 

The file metadata shows the change. The 600×400 upload:

curl "https://www.filestackapi.com/api/file/05kKe7H9Q0CA7T9fQ6Y0/metadata?width=true&height=true&size=true&mimetype=true"

{"height":400,"mimetype":"image/jpeg","size":84948,"width":600}

The upscaled copy:

{"height":800,"mimetype":"image/jpeg","size":390415,"width":1200}

Crop, resize, watermark and convert work as path segments too, alongside upscale in the same image editing API.

Key takeaways

  • We now include Image Upscaling on the Filestack Start, Grow and Scale plans at 1,000 images a month, then $0.025 an image.
  • upscale with no parameters returns exactly twice the width and height, in the format the file was uploaded in, with a PNG’s transparency intact.
  • The task accepts inputs up to 4,000,000 pixels, and a resize segment in front keeps any upload under that limit.
  • style:artwork draws harder outlines, and the default photo style stays closer to the source on illustrations as well as photographs.
  • The response is Cache-Control: public with 31 days of freshness, and a repeat request to the same URL is answered from cache.

How to call the image upscaling API

The task is one segment in front of the handle, and in its bare form it takes no parameters:

https://cdn.filestackcontent.com/upscale/HANDLE

HANDLE is the file handle an upload returns, the last segment of the file’s Filestack URL. Filled in with the 600×400 photograph from the figure above, that request returns a 1200×800 JPEG:

https://cdn.filestackcontent.com/upscale/05kKe7H9Q0CA7T9fQ6Y0

The output keeps the input’s format. A JPEG returns a JPEG, and a PNG returns a PNG with its transparency intact, so a 200×200 logo on a transparent background becomes a 400×400 one. To deliver something else, add output after the task, so upscale/output=format:webp/HANDLE returns a 1200×800 WebP.

In a React component the URL goes straight into an img tag, which is how a React upscaling app pairs it with the picker.

Whether a delivery URL needs a signed policy is a setting on your application. With security switched on, upscale answers an unsigned request, while ocr on the same handle returns 403 security required for tasks: ocr. Where your application does require a signed policy on delivery, sign one with the read and convert calls and put the security segment in front of the task:

https://cdn.filestackcontent.com/security=policy:POLICY,signature:SIGNATURE/upscale/HANDLE

A parameter value the task does not recognise returns a 400 that names the value. The fix is to send one of the values in the table below:

HTTP 400
validation error: invalid value format cartoon for parameter style required by upscale task (invalid value cartoon)

How upscale compares with resize

resize=width:1200 also turns a 600×400 file into a 1200×800 one, so matching dimensions alone do not show what upscale adds. The 600×400 upload in this example is a 1200×800 photograph shrunk to half size, so both outputs can be scored against that original.

A detail of a 600x400 fjord photograph doubled to 1200x800 twice, once with resize=width:1200 at similarity 0.842 to the original and once with upscale at 0.893
A detail of a 600×400 fjord photograph doubled to 1200×800 twice, once with resize=width:1200 at similarity 0.842 to the original and once with upscale at 0.893

 

resize stretches the pixels the file already has. upscale rebuilds detail at the new size and scores 0.893 SSIM similarity to the original against 0.842 for resize, where 1 is identical. On the first request, resize returns in about half a second and upscale in about 3 seconds.

Which upscale parameters are available

The task takes three parameters, each with a one-letter short form, and the Processing API reference lists them with the rest of the transformation tasks.

Parameter Short Values Default What it does
upscale u true, false true false keeps the input dimensions, which leaves noise as the only change.
noise n none, low, medium, high none Smooths grain as it scales. It also works with upscale:false.
style s photo, artwork photo artwork draws harder, darker edges. It has no effect with upscale:false.

With no parameters the task applies all three defaults, so upscale on its own returns the same file, byte for byte, as upscale=noise:none,style:photo,upscale:true. style only applies while the image is being enlarged, so with upscale:false it has no effect.

Combine parameters with a comma:

https://cdn.filestackcontent.com/upscale=noise:medium,style:photo/HANDLE

Repeating the segment doubles again, so upscale/upscale turns a 300×200 upload into 1200×800.

Join the Filestack developer community on Discord

When to use style artwork

The artwork style sharpens edges more aggressively than photo. The figure below doubles a 600×400 illustration with flat colour and dark outlines, then measures each result against the same illustration drawn at 1200×800.

A detail of a flat illustration at 600x400, then doubled with resize=width:1200 at PSNR 31.2 dB, with upscale at 43.5 dB, and with upscale=style:artwork at 40.7 dB
A detail of a flat illustration at 600×400, then doubled with resize=width:1200 at PSNR 31.2 dB, with upscale at 43.5 dB, and with upscale=style:artwork at 40.7 dB

 

Both styles beat resize by more than 9 dB. Between the two, the default photo style stays closer to the original, and artwork draws the outlines heavier than they were drawn. The same split shows on the photograph, where style:artwork raises edge sharpness by about 30% and scores 0.890 SSIM similarity against 0.893 for the default.

So artwork is a look rather than an accuracy setting. Use it where a heavier line suits the image, such as a logo or a cartoon avatar, and leave the default in place where the result has to match the source.

How the noise parameter behaves on grainy uploads

noise smooths grain while the image is enlarged. The figure below runs a grainy 600×400 photograph through all four levels.

A detail of a grainy 600x400 fjord photograph doubled through noise:none, low, medium and high, with sky grain measured at 14.9, 12.8, 9.9 and 11.0 against 2.2 for the clean original
A detail of a grainy 600×400 fjord photograph doubled through noise:none, low, medium and high, with sky grain measured at 14.9, 12.8, 9.9 and 11.0 against 2.2 for the clean original

 

Each level above none reduces the grain, and medium removes the most. SSIM similarity to the clean original rises from 0.464 with noise:none to 0.554 with medium or high. None of the levels restores a heavily grained file to the clean original.

On a clean file the same parameter removes detail. On the clean version of this photograph, similarity drops from 0.893 with noise:none to 0.886 with low and 0.874 with high. Choose noise per upload source. Leave it at none for clean originals, and use medium for a source that arrives grainy.

How large an image the upscale task accepts

The upscale task accepts inputs up to 4,000,000 pixels. A 2000×2000 input sits exactly on the limit and returns 4000×4000. A 2450×1633 input is 850 pixels over and returns this error:

HTTP 400
We're encountering an error with conv20gpu provider. Please connect with support. Error: The input image is too large. Maximum allowed size for upscale task is 4000000 pixels (failed task index 0)

The limit applies to the image as it reaches upscale, after any segment in front of it. A resize with fit:max shrinks anything larger than 2000×2000 to fit inside that box and leaves smaller images alone, so it keeps every upload under the limit:

https://cdn.filestackcontent.com/resize=width:2000,height:2000,fit:max/upscale/HANDLE

Through that URL, a 3000×2000 input returns 4000×2666, and the 600×400 photograph still returns 1200×800.

Processing time grows with the input. On the first request to a new URL, a 600×400 photograph takes about 3 seconds, a 1200×800 input about 7 seconds, and a 2400×1600 input about 26 seconds.

A file that is not an image returns a 400 naming its type, for example audio/mpeg conversions are not supported. Check the mimetype field in the upload response and send only image/* files to the task.

How to upscale a catalogue you already store

For a catalogue of existing images, run the task once per file from a server and keep the result. Adding store after upscale saves the output as a new file in your application’s storage and returns JSON describing it, with handle, size and type, instead of the image.

The script below needs Node.js 18 or later, which ships fetch, and your application secret in the FILESTACK_APP_SECRET environment variable. The secret comes from the Security section of your application in the developer portal, and it stays on the server. The script signs a policy with read, convert and store, the three calls the URL makes, in the security policy format.

// backfill-upscale.mjs
import crypto from 'node:crypto';

const APP_SECRET = process.env.FILESTACK_APP_SECRET;

function securitySegment() {
  const policy = Buffer.from(JSON.stringify({
    expiry: Math.floor(Date.now() / 1000) + 3600,
    call: ['read', 'convert', 'store'],
  })).toString('base64url');
  const signature = crypto.createHmac('sha256', APP_SECRET).update(policy).digest('hex');
  return `security=policy:${policy},signature:${signature}`;
}

async function upscaleAndStore(handle) {
  const tasks = 'resize=width:2000,height:2000,fit:max/upscale/store=location:s3';
  const url = `https://cdn.filestackcontent.com/${securitySegment()}/${tasks}/${handle}`;
  const response = await fetch(url);
  if (!response.ok) {
    throw new Error(`${handle} returned ${response.status}: ${await response.text()}`);
  }
  return response.json();
}

const handles = process.argv.slice(2);
for (const handle of handles) {
  try {
    const stored = await upscaleAndStore(handle);
    console.log(handle, '->', stored.handle, stored.size, stored.type);
  } catch (error) {
    console.error(error.message);
  }
}

Pass the handles as arguments:

node backfill-upscale.mjs q9o952p9QU6aJkYGWQEp zixfOafwSmKDAYJeb0FL 0jSokSPdTIq0vxRknqtY

For a 300×200 JPEG, a 200×200 transparent PNG and an MP3, the script prints:

q9o952p9QU6aJkYGWQEp -> v2TbPiYaSFvKZIxE82g1 105197 image/jpeg
zixfOafwSmKDAYJeb0FL -> 1Dfzd7pJSlCF1eMCs9Xb 74254 image/png
0jSokSPdTIq0vxRknqtY returned 400: We're encountering an error with Conversion provider. Please connect with support. Error: audio/mpeg conversions are not supported (failed task index 0)

Each run stores new files, so the handle after the arrow is different every time. The error names the failing task by its position in the URL. Index 0 is resize here, which rejected the MP3 before upscale was reached. The loop logs the failure and carries on, so one bad file does not stop a catalogue run. Record the new handle against the original in your own database, and deliver the stored copy from then on.

The script runs upscale once per handle, so count the handles before you start and compare the total with the 1,000 images included a month.

What Image Upscaling costs and how it caches

Upscaled output delivered by URL is cached at the CDN. The response carries cache-control: public, max-age=2678400, 31 days, and a repeat request to the same URL is served from cache with x-cache: MISS, HIT, without running the task again.

While the cached copy is fresh, a product page showing the same upscaled image to every visitor runs the task once for that URL rather than once per view. The included allowance is 1,000 images a month, then $0.025 an image, and the Filestack pricing page sets that against the other plan limits.

Because the first request to each URL runs the task, request each new URL once from your server with fetch(url) when the upload finishes. The next visitor then gets the cached copy rather than waiting for the task:

<img src="https://cdn.filestackcontent.com/resize=width:2000,height:2000,fit:max/upscale/HANDLE"
     alt="Product photograph">

Upscale before enhance on a small dark photo

A photograph that is both small and underexposed needs two tasks, and the order in the URL changes the file size more than the brightness. For an underexposed photograph about 600 pixels wide, both orders land within 2.5 points of mean luminance, and upscale first produces a file 33% to 42% smaller than enhance first:

https://cdn.filestackcontent.com/upscale/enhance=preset:fix_dark/HANDLE

Tasks run left to right, so with upscale first the correction runs on the pixels you deliver. Each image enhancement preset fits a different kind of upload, and fix_dark is the one for underexposure.

Which applications use image upscaling

Image upscaling fits images that are already stored at a size the page has outgrown. Examples are a product catalogue shot before retina screens, avatars uploaded at 96 pixels, and print on demand orders that arrive below print resolution.

For images delivered on a page, put upscale in the delivery URL with a resize in front of it. For a catalogue you are replacing, run the backfill script once and serve the stored copies.

FAQ

What is the difference between upscale and resize?

Resize stretches the pixels the file already has; upscale rebuilds detail at the new size. Scored against the same original, upscale reached 0.893 SSIM similarity to resize’s 0.842. The trade is time, about 3 seconds against half a second on a first request.

Why did my upscale call return a 400 about image size?

The input exceeded 4,000,000 pixels. The limit applies to the image as it reaches the task, so a resize=width:2000,height:2000,fit:max segment in front shrinks anything larger and leaves smaller files alone.

Should I set the noise parameter?

Only for sources that arrive grainy, where medium removes the most. On a clean file the same parameter removes detail, dropping similarity from 0.893 at none to 0.874 at high, so leave it off for clean originals.

Will every visitor trigger the task?

No. The response is Cache-Control: public with 31 days of freshness, so one URL runs the task once. Request each new URL from your server when the upload finishes, and the first visitor gets the cached copy rather than the wait.

Read More →