RGB565 to RGB unpacker
Read a 16-bit RGB565 value as a normal color: 0xF800, or 63488, is pure red, rgb 255, 0, 0 and #FF0000. Five red, six green and five blue bits are scaled to full range, with the stored levels shown. Free in your browser.
- Free
- Runs in your browser
- No sign-up
- Your data stays on your device
Run — free
Worked example
- Value
- 0xF800
- Value
- 63,488
- Hex rgb565
- 0xF800
- Red5
- 31
- Green6
- 0
This RGB565 to RGB unpacker converts one compact 16-bit color value into familiar 8-bit red, green, and blue channels. It validates that the input is an integer in the unsigned 16-bit range, separates the five red bits, six green bits, and five blue bits, then scales every channel deterministically to 0–255. Use decimal input or a hexadecimal value with a 0x prefix and receive the original packed value, component bit fields, an RGB string, and a six-digit hexadecimal color.
Understand the RGB565 layout
RGB565 stores a color in sixteen bits instead of the twenty-four bits used by ordinary 8-bit RGB. The most significant five bits represent red, the middle six bits represent green, and the least significant five bits represent blue. Green receives an extra bit because human vision is especially sensitive to changes in that part of the spectrum.
To unpack the value, this tool shifts and masks the integer into red values from 0 to 31, green values from 0 to 63, and blue values from 0 to 31. It then reports those reduced-depth components alongside their expanded equivalents. This makes the result useful both for developers who need a display-ready color and for engineers who want to inspect the exact bit fields stored in firmware, an embedded framebuffer, a binary asset, or a device protocol.
The reported four-digit hexadecimal form is padded consistently, so leading zeroes remain visible and comparisons stay straightforward.
See how reduced channels become 8-bit values
A reduced channel does not contain enough information to recover the original 8-bit sample exactly, so unpacking necessarily produces an approximation. This converter uses explicit proportional scaling and nearest-integer rounding. Red and blue are multiplied by 255, divided by 31, and rounded; green is multiplied by 255, divided by 63, and rounded.
Intermediate values are spread across the full 8-bit range without randomness or environment-dependent behavior. This rule is easy to reproduce in JavaScript, C, Rust, Python, or a spreadsheet, and the component fields in the output let you audit each step. Here the scaling rule is fixed and documented, making the output dependable for tests, asset conversion, protocol investigation, and cross-language comparisons.
Provide valid input and use the result
Enter one unsigned RGB565 value as decimal digits, such as 63488, or as hexadecimal with a required 0x prefix, such as 0xF800. The accepted range is 0 through 65535 inclusive because no larger value fits in sixteen bits. Negative numbers, fractions, bare hexadecimal letters, trailing characters, arrays, and unrelated objects are rejected instead of being partially parsed.
This strict behavior prevents an accidental value such as 65536 from wrapping to black and hiding an upstream data problem. Successful output includes the normalized decimal value, padded RGB565 hexadecimal, the original 5/6/5 components, scaled r, g, and b numbers, a CSS-style rgb() string, and a six-digit RGB hexadecimal string. You can feed the channel numbers into image code, compare the hexadecimal result in a debugging tool, or retain both packed and unpacked forms in a conversion log.
What you can do with it
Inspect embedded display colors
Convert framebuffer or firmware constants into familiar RGB values while retaining the original 5/6/5 channel fields.
Decode binary image assets
Unpack sampled 16-bit pixel words into 8-bit channels for diagnostics, previews, or a deterministic conversion pipeline.
FAQ
What input formats are accepted?
Use decimal digits from 0 to 65535 or hexadecimal with a 0x prefix, for example 63488 or 0xF800.
Why does green use six bits?
RGB565 allocates six bits to green and five each to red and blue, providing finer green gradation within a 16-bit word.
Can unpacking recover the exact original 8-bit color?
No. Packing discarded low-order information. The returned channels are deterministic approximations scaled across the complete 0–255 range.
How are channels scaled?
Red and blue use round(component × 255 ÷ 31); green uses round(component × 255 ÷ 63).
What happens if I enter 65536?
It is rejected. An RGB565 value has to fit in sixteen bits, so the accepted range is 0 through 65535; a larger number is refused instead of wrapping to black and hiding a mistake further up.
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/color/rgb565-rgb \
-H "Authorization: Bearer $KIT_KEY" \
-H "Content-Type: application/json" \
-d '{"value":"0xF800"}'const res = await fetch("https://api.kit.forhosting.com/color/rgb565-rgb", {
method: "POST",
headers: {
"Authorization": `Bearer ${process.env.KIT_KEY}`,
"Content-Type": "application/json"
},
body: JSON.stringify({
"value": "0xF800"
})
});
const { task_id } = await res.json();import os, requests
res = requests.post(
"https://api.kit.forhosting.com/color/rgb565-rgb",
headers={"Authorization": f"Bearer {os.environ['KIT_KEY']}"},
json={
"value": "0xF800"
},
)
task_id = res.json()["task_id"]<?php
$res = file_get_contents("https://api.kit.forhosting.com/color/rgb565-rgb", false, stream_context_create([
"http" => [
"method" => "POST",
"header" => "Authorization: Bearer " . getenv("KIT_KEY") . "\r\nContent-Type: application/json",
"content" => '{"value":"0xF800"}',
],
]));
$task = json_decode($res, true);body := bytes.NewBufferString(`{"value":"0xF800"}`)
req, _ := http.NewRequest("POST", "https://api.kit.forhosting.com/color/rgb565-rgb", body)
req.Header.Set("Authorization", "Bearer "+os.Getenv("KIT_KEY"))
req.Header.Set("Content-Type", "application/json")
res, _ := http.DefaultClient.Do(req)Example request
{
"value": "0xF800"
}Example response
{
"task_id": "tsk_a1b2c3d4e5f6a1b2c3d4e5f6",
"type": "color.rgb565_rgb",
"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.
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
See how reduced channels become 8-bit values
The endpoints therefore map exactly: zero becomes zero and every maximum component becomes 255.
Provide valid input and use the result
Browser execution is available for interactive checks, while automated requests cost $0.002 each through the API.
Integration use cases
Build cross-language fixtures
Generate explicit packed and scaled values to compare RGB565 implementations across application, device, and test code.
Technical questions
What happens when the value is outside the range?
The request returns an invalid_input error rather than wrapping, truncating, or interpreting extra bits.
What does API conversion cost?
Each API request costs $0.002; you can also run the conversion interactively in the browser.