Skip to content
Table of contents

HDR-10bpp-Display-Test: Packing ten-bit channels for a Cairo surface

This display experiment loads image data into a GTK drawing area through Cairo. Viewer3.py makes the pixel representation explicit: channel samples are masked and packed into a uint32 buffer before creating an RGB30 surface.

Hardware and graphics
  • Updated
  • 13
  • Python · 98.43%
Documented components
2Explore modules
Source documents
1Read the instructions
Repository languagesPython 98.43%2

Shares calculated from GitHub Linguist bytes.

Python98.43%
98.43%8,200 bytes
Shell1.57%
1.57%131 bytes
Language%Bytes
Python98.43%8,200
Shell1.57%131

1. Overview

1.1. Why it exists

10-bit HDR pipeline testing color banding and luminance curves on Linux display servers.

1.2. Best fit

Calibration and verification of 4K 10-bit HDR displays on Linux workstations.

2. Use cases

Linux scripts to check that an HDR display really shows 10 bits per channel under an X server at depth 30.

Use-case diagram for HDR-10bpp-Display-Test: Start X at depth 30; Show a 10-bit gray gradient; Compare 8-bit and 10-bit; Play a video at 10 bpcHDR-10bpp-Display-TestStart X at depth 30Show a 10-bit gray gradientCompare 8-bit and 10-bitPlay a video at 10 bpcDisplay tester«system»X server (Xorg)«system»HDR10 monitor
People on the left, external systems on the right; each oval is a use case backed by the files cited below.
Start X at depth 30
Display testerX server (Xorg)

Xdepth.sh runs startx -- -depth 30 and prints the depth from xwininfo, falling back to depth 24; xorg.conf sets DefaultDepth 30.

Show a 10-bit gray gradient
Display testerHDR10 monitor

Viewer.py packs the RGB channels of images/gray_gradient_10.tiff into a cairo FORMAT_RGB30 surface and draws it in a GTK 3 window.

Compare 8-bit and 10-bit
Display testerHDR10 monitor

The images/ folder holds gray_gradient_8.tiff next to gray_gradient_10.tiff, so the same gradient can be viewed at both depths to compare banding by eye.

Play a video at 10 bpc
Display testerHDR10 monitor

Viewer3.py adds a Typer CLI with --image-path and --video-path; videos are read frame by frame with imageio's ffmpeg reader in a thread at 30 fps.

2.1. Scenario: Checking a new HDR10 monitor on Ubuntu

  1. Stop the display manager: sudo systemctl stop lightdm || sudo systemctl stop gdm, then sudo pkill Xorg.
  2. Start X with startx -- -depth 30 (or run Xdepth.sh).
  3. Confirm with xwininfo -root | grep Depth that the root window reports depth 30.
  4. Run python3 Viewer.py to open images/gray_gradient_10.tiff in the viewer window.
  5. Look for banding in the gradient; smooth steps mean the 10-bit path works end to end.

Files readREADME.mdViewer.pyViewer3.pyXdepth.shxorg.conf

3. Getting started

These commands come from the repository documentation. They were not run during this review.

README.md · Prerequisites
sudo apt-get install xserver-xorg python3 python3-gi python3-gi-cairo gir1.2-gtk-3.0 imagej
README.md · Installing
pip3 install imageio
README.md · Running the test
git clone https://github.com/yourusername/HDR-10bpp-Display-Test.git
README.md · Running the test
cd HDR-10bpp-Display-Test
README.md · Running the test
sudo systemctl stop lightdm || sudo systemctl stop gdm
sudo pkill Xorg

4. Repository references

Excerpts from the repository’s guides, in their original language. Links open the inspected source revision.

Prerequisites and first run

4.1. Prerequisites

README.md

To run the test, you will need the following software installed on your system:

  • X server
  • Python 3
  • GTK 3
  • ImageJ (for displaying images with a 10-bit color depth)
  • ImageIO (for reading image files) You can install these packages on Ubuntu or Debian-based systems by running the following command:
Read the full instructions ↗

4.2. Installing

README.md

To install ImageIO, you can use pip:
Read the full instructions ↗
Operations and troubleshooting

4.3. Troubleshooting

README.md

If the X server does not start with a color depth of 30, try starting it with a color depth of 24:
Read the full instructions ↗
Development and contributions

4.4. HDR-10bpp-Display-Test

README.md

This is a simple test to verify the HDR 4K display on Linux using a color depth of 10 bits per channel. The test requires an HDR 4K display and a Linux environment with the X server installed.
Read the full instructions ↗

4.5. Running the test

README.md

To run the test, follow these steps:

  1. Clone the repository:
  2. Navigate to the project directory:
  3. Stop the display manager and X server:
  4. Start the X server with a color depth of 30:
  5. If the X server was started successfully, the output of the following command should indicate a depth of 30:
  6. Launch the viewer application:
  7. The viewer window will open. To display an image, run the following command:
  8. The image should be displayed in the viewer window. Verify that the image is displayed correctly and that the colors are accurate.
Read the full instructions ↗
Source documentation

1 documents read from 1 candidates.

5. Features and components 2

Pixels and drawing
imageio reads the source array. _draw_on allocates a packed buffer and shifts each channel according to the selected depth, then passes it to cairo.ImageSurface.create_for_data. The GTK draw callback paints that surface.
Video path
A worker reads video frames and updates the current image at a requested cadence. Drawing also manually processes pending GTK events. This older approach deserves particular attention to UI-thread ownership when maintained.

6. Architecture

Expand a component to follow its connections, or explore the full diagram.

System components Context
Mermaid Interactive diagram

System overview of the components and connections verified in the repository.

Static architecture view for HDR-10bpp-Display-Test
Static preview. The interactive diagram replaces it after Mermaid loads.
flowchart LR
node_user(("Test operator"))
node_imagej["ImageJ"]

subgraph group_setup["Display setup"]
  node_xserver["X server"]
end

subgraph group_viewers["Viewer applications"]
  node_viewer1["Image viewer<br/>[Viewer.py]"]
  node_viewer3["Image/video viewer<br/>[Viewer3.py]"]
end

subgraph group_render["Image rendering"]
  node_gtk1["GTK window<br/>[Viewer.py]"]
  node_gtk3["GTK window<br/>[Viewer3.py]"]
  node_imageio1["Image input<br/>[Viewer.py]"]
  node_imageio3["Image/video input<br/>[Viewer3.py]"]
  node_cairo1["Cairo drawing<br/>[Viewer.py]"]
  node_cairo3["Cairo drawing<br/>[Viewer3.py]"]
end

node_user -->|"starts at depth"| node_xserver
node_user -->|"launches"| node_viewer1
node_user -->|"launches"| node_viewer3
node_gtk1 -->|"dispatches draw"| node_cairo1
node_gtk3 -->|"dispatches draw"| node_cairo3
node_user -->|"opens image"| node_imagej
node_imagej -->|"displays for checking"| node_viewer1
group_viewers --> group_render
class node_xserver toneBlue
class node_viewer1,node_viewer3 toneAmber
class node_gtk1,node_gtk3,node_imageio1,node_imageio3,node_cairo1,node_cairo3 toneMint
class node_user,node_imagej toneIndigo

A Linux HDR and 10-bit display test. The workflow starts an X server at the requested depth, opens an image or video viewer, and draws frames through GTK and Cairo for visual checking.

Components
11
Connections
13
Evidence-backed links
13/13
Text version of the diagram

The diagram merges parallel links between groups, so it shows 8 of 13. Full list:

  • Test operator → X server (starts at depth)
  • Test operator → Image viewer (launches)
  • Test operator → Image/video viewer (launches)
  • Image viewer → GTK window (creates window)
  • Image viewer → Image input (reads image)
  • Image viewer → Cairo drawing (draws image)
  • GTK window → Cairo drawing (dispatches draw)
  • Image/video viewer → GTK window (creates window)
  • Image/video viewer → Image/video input (reads image/video)
  • Image/video viewer → Cairo drawing (draws frames)
  • GTK window → Cairo drawing (dispatches draw)
  • Test operator → ImageJ (opens image)
  • ImageJ → Image viewer (displays for checking)
Follow one path through the code

Inspect _draw_on to see exactly where bit depth affects shifts and surface selection. Ten-bit storage concerns numeric precision; HDR transfer functions, metadata and display calibration require additional work outside this packing step.

7. Technical dossier

Built from the source at commit 9c72e07 (4 files). Each item comes from a pattern match in the code, so open the linked file before relying on it.

7.1. Layers and modules

Folders are sorted into layers by name, from the user interface down to data access. Because the sorting uses names only, the diagram says nothing about calls between layers.

Mermaid Layered view
flowchart TB
  subgraph L_core["Core source"]
    direction TB
    core_0["(root)<br/>3 files"]
  end
Modules and their main layer
ModuleLayerFilesTypesExtensions
(root)Core source32.py .sh

7.2. C4 model

From system context to code declarations. Each level reflects the available source evidence.

UML 1 · System context
1 · System context

The widest C4 view: who uses the project and which outside systems and data stores it relies on. Rendered with uml-mcp.

PlantUML source
@startuml
!include <C4/C4_Context>
LAYOUT_LEFT_RIGHT()
System(SYS, "HDR-10bpp-Display-Test", "This display experiment loads image data into a GTK drawing area thro…")
@enduml

Level 2: the available sources do not support this view.

UML 3 · Components and layers
3 · Components and layers

Modules grouped by source-layer classification. Boundaries show organization, not runtime isolation or call relationships. Rendered with uml-mcp.

PlantUML source
@startuml
!include <C4/C4_Component>
LAYOUT_TOP_DOWN()
System_Boundary(SYS, "HDR-10bpp-Display-Test") {
Boundary(L0, "Core source", "layer") {
Component(M0_0, "(root)", "Python, .sh", "3 files")
}
}
@enduml
UML 4 · Code
4 · Code

Selected declarations, fields and methods grouped by source file. No inheritance or call edges are inferred. Rendered with uml-mcp.

PlantUML source
@startuml
skinparam backgroundColor transparent
skinparam shadowing false
skinparam roundCorner 10
skinparam defaultFontName Arial
skinparam defaultFontSize 13
skinparam ArrowColor #4e6070
skinparam ArrowFontColor #3d4f5f
skinparam titleFontSize 14
skinparam actorBorderColor #006a62
skinparam actorBackgroundColor #e9f3f4
skinparam usecaseBorderColor #006a62
skinparam usecaseBackgroundColor #e9f3f4
skinparam componentBorderColor #006a62
skinparam componentBackgroundColor #e9f3f4
skinparam interfaceBorderColor #006a62
skinparam interfaceBackgroundColor #ffffff
skinparam nodeBorderColor #4e6070
skinparam nodeBackgroundColor #f4f8fb
skinparam databaseBorderColor #006a62
skinparam databaseBackgroundColor #ffffff
skinparam cloudBorderColor #4e6070
skinparam cloudBackgroundColor #f0f5fa
skinparam artifactBorderColor #006a62
skinparam artifactBackgroundColor #ffffff
skinparam rectangleBorderColor #b0c2d3
skinparam activityBorderColor #006a62
skinparam activityBackgroundColor #e9f3f4
skinparam partitionBorderColor #b0c2d3
skinparam stereotypeCBackgroundColor #ffffff
top to bottom direction
hide empty members
package "HDR-10bpp-Display-Test" {
package "Viewer3.py" as F0 {
class "Viewer" as T0_0 {
  _initUI()
  _window_state()
  size()
  fullscreen()
  display_image()
  _draw()
}
}
}
@enduml

7.3. Data flow

The calls from the GitDiagram graph, in the order you meet them from the entry points. GitDiagram generates the graph with AI; the file paths it cites were checked against the repository tree.

Mermaid Sequence diagram
sequenceDiagram
  autonumber
  participant P0 as Test operator
  participant P1 as X server
  participant P2 as Image viewer
  participant P3 as Image/video viewer
  participant P4 as ImageJ
  participant P5 as GTK window
  participant P6 as Image input
  participant P7 as Cairo drawing
  participant P8 as Image/video input
  P0->>P1: starts at depth
  P0->>P2: launches
  P0->>P3: launches
  P0->>P4: opens image
  P2->>P5: creates window
  P2->>P6: reads image
  P2->>P7: draws image
  P3->>P5: creates window
  P3->>P8: reads image/video
  P3->>P7: draws frames
  P4->>P2: displays for checking
  P5->>P7: dispatches draw
  P5->>P7: dispatches draw
Steps as text
  1. Test operator to X server starts at depth
  2. Test operator to Image viewer launches
  3. Test operator to Image/video viewer launches
  4. Test operator to ImageJ opens image
  5. Image viewer to GTK window creates window
  6. Image viewer to Image input reads image
  7. Image viewer to Cairo drawing draws image
  8. Image/video viewer to GTK window creates window
  9. Image/video viewer to Image/video input reads image/video
  10. Image/video viewer to Cairo drawing draws frames
  11. ImageJ to Image viewer displays for checking
  12. GTK window to Cairo drawing dispatches draw
  13. GTK window to Cairo drawing dispatches draw

7.4. Private interface

These names are internal by the language’s conventions: a leading underscore, private, static or pub(crate).

underscore helper
11

7.5. Business logic

Once UI code and the services and entities above are set aside, these classes have the most methods.

Viewer Core source, 12 methods
_initUI, _window_state, size, fullscreen, display_image, _draw

7.6. CI/CD pipeline

No CI/CD pipeline in the repository. The code is built and run by hand, as described above.

7.7. Deployment

Mermaid Deployment diagram
flowchart LR
  repo[("GitHub repository")]
  local["Local machine"]
  repo -->|"clone and run"| local

The repository has no Dockerfile, Compose file or hosting configuration, so the code runs on the machine that clones it.

The available sources do not document the remaining sections.

8. Types and file structure

2 declared types, with 2 in the base-relationship overview.

Type diagram
classDiagram
direction TB
class td926548d9d56["Viewer"] {
  __init__()
  _initUI()
  _window_state()
  size()
}
class t015018d2192b["Viewer"] {
  __init__()
  _initUI()
  _window_state()
  size()
}
class bb574778f1f7f["object"] {
  <<unresolved_base>>
}
bb574778f1f7f <|-- td926548d9d56
class ba71980200e35["object"] {
  <<unresolved_base>>
}
ba71980200e35 <|-- t015018d2192b

Unresolved bases remain labelled; full signatures are not reconstructed.

9. Reference

4 / 4 eligible files read (7 in the tree); 0 oversized, 0 failed reads and 0 syntax diagnostics.

What the scan covers

Known dependency/build folders, credential files and binaries are excluded. The scan covers READMEs, recognized manifests and parser-supported source files.

Linguist statistics cover the whole repository and may include other languages.

11. Files to read 3

12. Glossary

Repository

The versioned source files, configuration, and history of a project.

README

The repository’s entry document, usually covering its purpose and initial setup.

Dependency

A library, tool, or service that another component needs to build or run.

Volume and bind mount

A volume is storage managed by the container platform; a bind mount exposes a chosen host path inside a container.

CLI

A text interface in which commands and arguments select operations. Exit codes let scripts detect success or failure.

Webhook

An HTTP request sent to another system when an event occurs. The receiver needs to validate the request before acting on it.

13. References

  1. antoinebou12. (2026, November 5). HDR-10bpp-Display-Test. [Software repository] github.com.
  2. antoinebou12. (2026, November 5). HDR-10bpp-Display-Test: README. [Repository documentation] github.com.
  3. antoinebou12. (2026, November 5). Viewer3.py. [Source file] github.com.
  4. antoinebou12. (2026, November 5). Xdepth.sh. [Source file] github.com.
  5. antoinebou12. (2026, November 5). xorg.conf. [Source file] github.com.
  6. Boucher, A. (2024, January 1). HDR-10bpp-Display-Test. [Project article] antoineboucher.info.
  7. Boucher, A. (2026, October 23). HDR-10bpp-Display-Test: Packing ten-bit channels for a Cairo surface. [Project article] antoineboucher.info.

Sources without a publication date show the date they were last checked, November 5, 2026. File links retain the inspected revision where available.