# Upscaling Images

Source: https://docs.prodia.com/guides/upscaling-images/

We're going to walk through how to take a small, low-resolution image and upscale it to a higher resolution using the upscale endpoint. This is useful for sharpening generated thumbnails, restoring detail in old photos, or producing print-ready assets.

We'll be using a 384x384 lighthouse photo as our input image:

![upscale-input.jpg](https://docs.prodia.com/llms/assets/72db300e60c6-upscale-input.jpg)

### Project Setup

```bash
# Create a project directory.
mkdir prodia-upscaling-images
cd prodia-upscaling-images
```

### prodia-js

Install Node (if not already installed):

### macOS

```bash
brew install node
# Close the current terminal and open a new one so that node is available.
```

### Linux

```bash
apt install node
# Close the current terminal and open a new one so that node is available.
```

### Windows

```bash
winget install -e --id OpenJS.NodeJS.LTS
# Close the current terminal and open a new one so that node is available.
```

Create project skeleton:

```bash
# Requires node --version >= 18
# Initialize the project with npm.
npm init -y

# Install the prodia-js library.
npm install prodia --save
```

### requests

Install Python (if not already installed):

### macOS

```bash
brew install python
# Close the current terminal and open a new one so that python is available.
```

### Linux

```bash
apt install python3 python3-venv python-is-python3
# Close the current terminal and open a new one so that python is available.
```

### Windows

```bash
winget install -e --id Python.Python.3.12
# Close the current terminal and open a new one so that python is available.
```

```bash
# Requires python --version >= 3.12
python -m venv venv
source venv/bin/activate
pip install requests
```

### curl

Install curl (if not already installed):

### macOS

```bash
brew install curl
# Close the current terminal and open a new one so that curl is available.
```

### Linux

```bash
apt install curl
# Close the current terminal and open a new one so that curl is available.
```

### Windows

```bash
# NOTE: Windows 10 and up have curl installed by default and this can be
# skipped.
winget install -e --id cURL.cURL
# Close the current terminal and open a new one so that curl is available.
```

```bash
# Export your token so it can be used by the main code.
export PRODIA_TOKEN=your-token-here
```

> note:
>
> Your token is exported to an environment variable. If you close or switch your
> shell you'll need to run `export PRODIA_TOKEN=your-token-here` again.

Create a main file for your project:

### prodia-js

```js title="main.js"
const { createProdia } = require("prodia/v2");

const prodia = createProdia({
    token: process.env.PRODIA_TOKEN // get it from environment
});
```

### requests

Create the following `main.py`

```python title="main.py"
from requests.adapters import HTTPAdapter, Retry
import os
import requests
import sys


prodia_token = os.getenv('PRODIA_TOKEN')
prodia_url = 'https://inference.prodia.com/v2/job'

session = requests.Session()
retries = Retry(allowed_methods=None, status_forcelist=Retry.RETRY_AFTER_STATUS_CODES)
session.mount('http://', HTTPAdapter(max_retries=retries))
session.mount('https://', HTTPAdapter(max_retries=retries))
session.headers.update({'Authorization': f"Bearer {prodia_token}"})
```

### curl

```bash title="main.sh"
set -euo pipefail
```

You're now ready to make some API calls!

### Upscale 2x

The upscale endpoint accepts a single image and returns a larger version of it. The `upscale` config field controls the factor — `2`, `4`, or `8`.

### prodia-js

```javascript
const { createProdia } = require("prodia/v2");
const fs = require("node:fs/promises");

const prodia = createProdia({
  token: process.env.PRODIA_TOKEN,
});

(async () => {
  // get input image
  const inputBuffer = await (await fetch("https://docs.prodia.com/upscale-input.jpg")).arrayBuffer();

  const job = await prodia.job({
    type: "inference.upscale.v1",
    config: {
      upscale: 2,
    },
  }, {
    inputs: [ inputBuffer ]
  });

  const image = await job.arrayBuffer();
  await fs.writeFile("upscaled.jpg", new Uint8Array(image));
})();
```

```bash
node main.js
```

### requests

```python
from requests.adapters import HTTPAdapter, Retry
from io import BytesIO
import json
import os
import requests
import sys


prodia_token = os.getenv('PRODIA_TOKEN')
prodia_url = 'https://inference.prodia.com/v2/job'

session = requests.Session()
retries = Retry(allowed_methods=None, status_forcelist=Retry.RETRY_AFTER_STATUS_CODES)
session.mount('http://', HTTPAdapter(max_retries=retries))
session.mount('https://', HTTPAdapter(max_retries=retries))
session.headers.update({'Authorization': f"Bearer {prodia_token}"})

try:
    with open('upscale-input.jpg', 'rb') as f:
        input_image = f.read()
except FileNotFoundError:
    res = requests.get('https://docs.prodia.com/upscale-input.jpg')
    input_image = res.content
    with open('upscale-input.jpg', 'wb') as f:
        f.write(res.content)

headers = {
    'Accept': 'image/jpeg',
}

job = {
    'type': 'inference.upscale.v1',
    'config': {
        'upscale': 2,
    },
}

files = [
    ('job', ('job.json', BytesIO(json.dumps(job).encode('utf-8')), 'application/json')),
    ('input', ('upscale-input.jpg', input_image, 'image/jpeg')),
]

res = session.post(prodia_url, headers=headers, files=files)
print(f"Request ID: {res.headers['x-request-id']}")
print(f"Status: {res.status_code}")

if res.status_code != 200:
    print(res.text)
    sys.exit(1)

with open('upscaled.jpg', 'wb') as f:
    f.write(res.content)
```

```bash
python main.py
```

### curl

```bash
set -euo pipefail

cat <<EOF > job.json
{
  "type": "inference.upscale.v1",
  "config": {
    "upscale": 2
  }
}
EOF

if [[ ! -f upscale-input.jpg ]]; then
  curl -Lo upscale-input.jpg 'https://docs.prodia.com/upscale-input.jpg'
fi

curl -sSf --retry 3 \
  -H "Authorization: Bearer $PRODIA_TOKEN" \
  -H 'Accept: image/jpeg' \
  -F job=@job.json \
  -F input=@upscale-input.jpg \
  --output upscaled.jpg \
  https://inference.prodia.com/v2/job
```

```bash
bash main.sh
```

### macOS

```bash
open upscaled.jpg
```

### Linux

```bash
xdg-open upscaled.jpg
```

### Windows

```bash
start upscaled.jpg
```

The 384x384 input is now a sharp 768x768 image. Edges around the lighthouse and rocks have crisper detail and the JPEG compression artifacts in the sky are gone:

![upscale-output.jpg](https://docs.prodia.com/llms/assets/071415d07f00-upscale-output.jpg)

### Upscale 4x

For larger outputs, set `upscale` to `4` or `8`. The endpoint returns the same dimensions multiplied by the chosen factor — for our 384x384 input, `upscale: 4` produces a 1536x1536 image.

### prodia-js

```javascript
const { createProdia } = require("prodia/v2");
const fs = require("node:fs/promises");

const prodia = createProdia({
  token: process.env.PRODIA_TOKEN,
});

(async () => {
  // get input image
  const inputBuffer = await (await fetch("https://docs.prodia.com/upscale-input.jpg")).arrayBuffer();

  const job = await prodia.job({
    type: "inference.upscale.v1",
    config: {
      upscale: 4,
    },
  }, {
    inputs: [ inputBuffer ]
  });

  const image = await job.arrayBuffer();
  await fs.writeFile("upscaled-4x.jpg", new Uint8Array(image));
})();
```

```bash
node main.js
```

### requests

```python
from requests.adapters import HTTPAdapter, Retry
from io import BytesIO
import json
import os
import requests
import sys


prodia_token = os.getenv('PRODIA_TOKEN')
prodia_url = 'https://inference.prodia.com/v2/job'

session = requests.Session()
retries = Retry(allowed_methods=None, status_forcelist=Retry.RETRY_AFTER_STATUS_CODES)
session.mount('http://', HTTPAdapter(max_retries=retries))
session.mount('https://', HTTPAdapter(max_retries=retries))
session.headers.update({'Authorization': f"Bearer {prodia_token}"})

try:
    with open('upscale-input.jpg', 'rb') as f:
        input_image = f.read()
except FileNotFoundError:
    res = requests.get('https://docs.prodia.com/upscale-input.jpg')
    input_image = res.content
    with open('upscale-input.jpg', 'wb') as f:
        f.write(res.content)

headers = {
    'Accept': 'image/jpeg',
}

job = {
    'type': 'inference.upscale.v1',
    'config': {
        'upscale': 4,
    },
}

files = [
    ('job', ('job.json', BytesIO(json.dumps(job).encode('utf-8')), 'application/json')),
    ('input', ('upscale-input.jpg', input_image, 'image/jpeg')),
]

res = session.post(prodia_url, headers=headers, files=files)
print(f"Request ID: {res.headers['x-request-id']}")
print(f"Status: {res.status_code}")

if res.status_code != 200:
    print(res.text)
    sys.exit(1)

with open('upscaled-4x.jpg', 'wb') as f:
    f.write(res.content)
```

```bash
python main.py
```

### curl

```bash
set -euo pipefail

cat <<EOF > job.json
{
  "type": "inference.upscale.v1",
  "config": {
    "upscale": 4
  }
}
EOF

if [[ ! -f upscale-input.jpg ]]; then
  curl -Lo upscale-input.jpg 'https://docs.prodia.com/upscale-input.jpg'
fi

curl -sSf --retry 3 \
  -H "Authorization: Bearer $PRODIA_TOKEN" \
  -H 'Accept: image/jpeg' \
  -F job=@job.json \
  -F input=@upscale-input.jpg \
  --output upscaled-4x.jpg \
  https://inference.prodia.com/v2/job
```

```bash
bash main.sh
```

### macOS

```bash
open upscaled-4x.jpg
```

### Linux

```bash
xdg-open upscaled-4x.jpg
```

### Windows

```bash
start upscaled-4x.jpg
```

At 4x, the rocks gain individual texture and the clouds resolve into distinct shapes:

![upscaled-4x.jpg](https://docs.prodia.com/llms/assets/ece163bb0ef3-upscale-output-4x.jpg)

### Parameters

| Parameter | Type   | Values        | Default | Description                                                      |
| --------- | ------ | ------------- | ------- | ---------------------------------------------------------------- |
| `upscale` | number | `2`, `4`, `8` | `2`     | How many times larger the output should be along each dimension. |

### Picking a factor

| Goal                                                        | Factor |
| ----------------------------------------------------------- | ------ |
| Sharpen a generated image without changing dimensions much  | `2`    |
| Produce a print-ready or hero-banner asset from a thumbnail | `4`    |
| Maximum resolution for archival or large-format display     | `8`    |

Outputs scale quadratically — an 8x upscale of a 1024x1024 input produces an 8192x8192 image (around 67 megapixels), so prefer the smallest factor that meets your needs.

### See also

[Restoring Faces](https://docs.prodia.com/guides/restoring-faces/) — If your input contains faces, run face restoration first or use the combined facerestore.upscale endpoint.

[Generating Images](https://docs.prodia.com/guides/generating-images/) — Generate a base image at lower resolution, then upscale to save time and cost.
