Fit an image with letterbox bars
Fit a picture inside a fixed canvas without cropping or stretching: a 1920 by 1080 image in a 1000 by 1000 square becomes 1000 by 562, with 219-pixel bars above and below. Free in your browser.
- Free
- Runs in your browser
- No sign-up
- Your data stays on your device
Run — free
Worked example
- Source width
- 1,920
- Source height
- 1,080
- Canvas width
- 1,000
- Canvas height
- 1,000
- Scale
- 0.5208333333
- Fit
- letterbox
Fit an image inside a fixed canvas without guessing, stretching, or cutting away content. Enter the source width and height plus the target canvas dimensions to receive the uniform scale, final integer pixel size, and the exact top, right, bottom, and left bars. The result distinguishes letterboxing, pillarboxing, and an exact aspect-ratio match, making it useful for video frames, presentation layouts, image pipelines, responsive previews, and any workflow that must preserve the complete source image.
Fit the whole image while preserving its shape
A contain-style fit has one strict promise: every source pixel remains visible inside the target canvas. The calculator compares the source and canvas aspect ratios, chooses the smaller of the horizontal and vertical scale factors, and applies that single factor to both image dimensions. Because the width and height always change together, circles stay circular, faces are not squeezed, and the composition is never cropped.
The returned fitted width and height are integer pixel dimensions that do not exceed the canvas. When an exact proportional dimension falls between pixels, the constrained dimension fills its canvas edge and the other dimension rounds down. Rounding down is intentional because rounding up could place a row or column outside the requested canvas.
The response also includes the mathematical scale before pixel rounding, which is useful when configuring graphics software or comparing several candidate canvas sizes. All four input dimensions must be positive integers; a zero dimension has no usable aspect ratio and is rejected as invalid input rather than producing an infinite or undefined result.
Read letterbox and pillarbox bar measurements
The bars object gives padding in pixels for the top, right, bottom, and left sides of the fitted image. A wide image placed in a relatively tall canvas leaves unused vertical space, so the result is letterboxed with bars above and below. A tall or narrow image placed in a relatively wide canvas leaves horizontal space, producing pillarbox bars on the left and right.
If source and canvas share the same aspect ratio, the fit is exact and every bar is zero. The image is centered in every case. When the unused number of pixels is even, opposite bars have equal sizes.
When it is odd, the top or left receives the smaller share and the bottom or right receives the remaining pixel. This deterministic convention makes the four bars add back to the canvas dimensions exactly and avoids ambiguous half-pixel placement. You can use the bar values directly as padding, offsets, or drawing coordinates: the image origin is at left and top, while the fitted rectangle ends before the right and bottom bars.
Apply the result in rendering and media pipelines
Use these numbers before resizing rather than after exporting an image. First create or select the target canvas, resize the source to the returned fitted width and height with your preferred resampling method, then place it at the returned left and top offsets. Fill the remaining canvas area with a solid color, transparency, a blurred extension, or another background treatment.
The calculation itself does not inspect image bytes, choose a color, or perform resampling; it is a geometry step that stays independent of file format and rendering library. That separation makes the output equally useful with CSS, Canvas, SVG, FFmpeg, ImageMagick, mobile drawing APIs, presentation software, or server-side thumbnail jobs. For batch systems, validate dimensions early and store the fit result beside the render request so later stages use one agreed geometry.
What you can do with it
Prepare video frames
Fit footage or still artwork into a fixed output resolution and obtain exact bar sizes before encoding.
Build uncropped previews
Center product photos, portfolio images, or document previews inside uniform cards without removing any content.
Plan presentation layouts
Calculate the image rectangle and balanced padding for slides, digital signage, and display canvases.
FAQ
What does the calculation cost?
The calculation is also available free in the browser.
Does this crop or stretch the image?
No. It applies one uniform scale to both dimensions, keeps the entire image visible, and uses bars for unused canvas space.
Why are opposite bars sometimes one pixel different?
An odd amount of unused space cannot be divided equally into integer pixels. The extra pixel is assigned to the right or bottom bar.
What happens when the aspect ratios already match?
The fit is reported as exact, the fitted image fills the canvas, and all four bar sizes are zero.
Can I use zero for an unknown dimension?
No. Every source and canvas dimension must be a positive integer because zero cannot define a valid aspect ratio.
Does the capability resize an image file?
No. It calculates geometry only. Use the returned fitted size and offsets with the image or video renderer of your choice.
Related tools
For developers — API access
Everything on this page is available programmatically. This section is for teams who want to wire it into their own systems; everyone else can just use the tool above.
API endpoint
Prefer to automate it? One authenticated POST creates the task; the result comes back by webhook or a signed link. The same capability also runs here on the web, by email and from Telegram — and soon from our app too.
Call it from your stack
curl -X POST https://api.kit.forhosting.com/image/letterbox-fit \
-H "Authorization: Bearer $KIT_KEY" \
-H "Content-Type: application/json" \
-d '{"source_width":1920,"source_height":1080,"canvas_width":1000,"canvas_height":1000}'const res = await fetch("https://api.kit.forhosting.com/image/letterbox-fit", {
method: "POST",
headers: {
"Authorization": `Bearer ${process.env.KIT_KEY}`,
"Content-Type": "application/json"
},
body: JSON.stringify({
"source_width": 1920,
"source_height": 1080,
"canvas_width": 1000,
"canvas_height": 1000
})
});
const { task_id } = await res.json();import os, requests
res = requests.post(
"https://api.kit.forhosting.com/image/letterbox-fit",
headers={"Authorization": f"Bearer {os.environ['KIT_KEY']}"},
json={
"source_width": 1920,
"source_height": 1080,
"canvas_width": 1000,
"canvas_height": 1000
},
)
task_id = res.json()["task_id"]<?php
$res = file_get_contents("https://api.kit.forhosting.com/image/letterbox-fit", false, stream_context_create([
"http" => [
"method" => "POST",
"header" => "Authorization: Bearer " . getenv("KIT_KEY") . "\r\nContent-Type: application/json",
"content" => '{"source_width":1920,"source_height":1080,"canvas_width":1000,"canvas_height":1000}',
],
]));
$task = json_decode($res, true);body := bytes.NewBufferString(`{"source_width":1920,"source_height":1080,"canvas_width":1000,"canvas_height":1000}`)
req, _ := http.NewRequest("POST", "https://api.kit.forhosting.com/image/letterbox-fit", body)
req.Header.Set("Authorization", "Bearer "+os.Getenv("KIT_KEY"))
req.Header.Set("Content-Type", "application/json")
res, _ := http.DefaultClient.Do(req)Example request
{
"source_width": 1920,
"source_height": 1080,
"canvas_width": 1000,
"canvas_height": 1000
}Example response
{
"task_id": "tsk_a1b2c3d4e5f6a1b2c3d4e5f6",
"type": "image.letterbox_fit",
"status": "queued",
"_links": {
"result": "/tasks/tsk_…/result"
}
}The API is asynchronous: the call returns a task_id immediately and the result arrives by webhook. Polling is capped at 1 req/s per task.
Pricing
Published price — no tokens, no invented credits. A failed task is never charged.
Limits
max_mb | 15 |
max_megapixels | 12 |
Errors
| HTTP | Code | Meaning |
|---|---|---|
401 | unauthorized | Missing or invalid API key. |
402 | insufficient_balance | Your balance doesn't cover the task price. |
404 | unknown_type | That task type doesn't exist. |
429 | rate_limited | Too many requests. Use the webhook instead of polling. |
Technical notes
Apply the result in rendering and media pipelines
The API request costs $0.002, while the same deterministic calculation can run in the browser.