You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

704 lines
30 KiB

  1. # Quantum Painter :id=quantum-painter
  2. Quantum Painter is the standardised API for graphical displays. It currently includes support for basic drawing primitives, as well as custom images, animations, and fonts.
  3. Due to the complexity, there is no support for Quantum Painter on AVR-based boards.
  4. To enable overall Quantum Painter to be built into your firmware, add the following to `rules.mk`:
  5. ```make
  6. QUANTUM_PAINTER_ENABLE = yes
  7. QUANTUM_PAINTER_DRIVERS = ......
  8. ```
  9. You will also likely need to select an appropriate driver in `rules.mk`, which is listed below.
  10. !> Quantum Painter is not currently integrated with system-level operations such as disabling displays after a configurable timeout, or when the keyboard goes into suspend. Users will need to handle this manually at the current time.
  11. The QMK CLI can be used to convert from normal images such as PNG files or animated GIFs, as well as fonts from TTF files.
  12. Hardware supported:
  13. | Display Panel | Panel Type | Size | Comms Transport | Driver |
  14. |---------------|--------------------|------------------|-----------------|-----------------------------------------|
  15. | GC9A01 | RGB LCD (circular) | 240x240 | SPI + D/C + RST | `QUANTUM_PAINTER_DRIVERS = gc9a01_spi` |
  16. | ILI9163 | RGB LCD | 128x128 | SPI + D/C + RST | `QUANTUM_PAINTER_DRIVERS = ili9163_spi` |
  17. | ILI9341 | RGB LCD | 240x320 | SPI + D/C + RST | `QUANTUM_PAINTER_DRIVERS = ili9341_spi` |
  18. | SSD1351 | RGB OLED | 128x128 | SPI + D/C + RST | `QUANTUM_PAINTER_DRIVERS = ssd1351_spi` |
  19. | ST7789 | RGB LCD | 240x320, 240x240 | SPI + D/C + RST | `QUANTUM_PAINTER_DRIVERS = st7789_spi` |
  20. ## Quantum Painter Configuration :id=quantum-painter-config
  21. | Option | Default | Purpose |
  22. |-----------------------------------------|---------|---------------------------------------------------------------------------------------------------------------------------------------------|
  23. | `QUANTUM_PAINTER_NUM_IMAGES` | `8` | The maximum number of images/animations that can be loaded at any one time. |
  24. | `QUANTUM_PAINTER_NUM_FONTS` | `4` | The maximum number of fonts that can be loaded at any one time. |
  25. | `QUANTUM_PAINTER_CONCURRENT_ANIMATIONS` | `4` | The maximum number of animations that can be executed at the same time. |
  26. | `QUANTUM_PAINTER_LOAD_FONTS_TO_RAM` | `FALSE` | Whether or not fonts should be loaded to RAM. Relevant for fonts stored in off-chip persistent storage, such as external flash. |
  27. | `QUANTUM_PAINTER_PIXDATA_BUFFER_SIZE` | `32` | The limit of the amount of pixel data that can be transmitted in one transaction to the display. Higher values require more RAM on the MCU. |
  28. | `QUANTUM_PAINTER_SUPPORTS_256_PALETTE` | `FALSE` | If 256-color palettes are supported. Requires significantly more RAM on the MCU. |
  29. | `QUANTUM_PAINTER_DEBUG` | _unset_ | Prints out significant amounts of debugging information to CONSOLE output. Significant performance degradation, use only for debugging. |
  30. Drivers have their own set of configurable options, and are described in their respective sections.
  31. ## Quantum Painter CLI Commands :id=quantum-painter-cli
  32. ### `qmk painter-convert-graphics`
  33. This command converts images to a format usable by QMK, i.e. the QGF File Format.
  34. **Usage**:
  35. ```
  36. usage: qmk painter-convert-graphics [-h] [-d] [-r] -f FORMAT [-o OUTPUT] -i INPUT [-v]
  37. optional arguments:
  38. -h, --help show this help message and exit
  39. -d, --no-deltas Disables the use of delta frames when encoding animations.
  40. -r, --no-rle Disables the use of RLE when encoding images.
  41. -f FORMAT, --format FORMAT
  42. Output format, valid types: pal256, pal16, pal4, pal2, mono256, mono16, mono4, mono2
  43. -o OUTPUT, --output OUTPUT
  44. Specify output directory. Defaults to same directory as input.
  45. -i INPUT, --input INPUT
  46. Specify input graphic file.
  47. -v, --verbose Turns on verbose output.
  48. ```
  49. The `INPUT` argument can be any image file loadable by Python's Pillow module. Common formats include PNG, or Animated GIF.
  50. The `OUTPUT` argument needs to be a directory, and will default to the same directory as the input argument.
  51. The `FORMAT` argument can be any of the following:
  52. | Format | Meaning |
  53. |-----------|-----------------------------------------------------------------------|
  54. | `pal256` | 256-color palette (requires `QUANTUM_PAINTER_SUPPORTS_256_PALETTE`) |
  55. | `pal16` | 16-color palette |
  56. | `pal4` | 4-color palette |
  57. | `pal2` | 2-color palette |
  58. | `mono256` | 256-shade grayscale (requires `QUANTUM_PAINTER_SUPPORTS_256_PALETTE`) |
  59. | `mono16` | 16-shade grayscale |
  60. | `mono4` | 4-shade grayscale |
  61. | `mono2` | 2-shade grayscale |
  62. **Examples**:
  63. ```
  64. $ cd /home/qmk/qmk_firmware/keyboards/my_keeb
  65. $ qmk painter-convert-graphics -f mono16 -i my_image.gif -o ./generated/
  66. Writing /home/qmk/qmk_firmware/keyboards/my_keeb/generated/my_image.qgf.h...
  67. Writing /home/qmk/qmk_firmware/keyboards/my_keeb/generated/my_image.qgf.c...
  68. ```
  69. ### `qmk painter-make-font-image`
  70. This command converts a TTF font to an intermediate format for editing, before converting to the QFF File Format.
  71. **Usage**:
  72. ```
  73. usage: qmk painter-make-font-image [-h] [-a] [-u UNICODE_GLYPHS] [-n] [-s SIZE] -o OUTPUT -f FONT
  74. optional arguments:
  75. -h, --help show this help message and exit
  76. -a, --no-aa Disable anti-aliasing on fonts.
  77. -u UNICODE_GLYPHS, --unicode-glyphs UNICODE_GLYPHS
  78. Also generate the specified unicode glyphs.
  79. -n, --no-ascii Disables output of the full ASCII character set (0x20..0x7E), exporting only the glyphs specified.
  80. -s SIZE, --size SIZE Specify font size. Default 12.
  81. -o OUTPUT, --output OUTPUT
  82. Specify output image path.
  83. -f FONT, --font FONT Specify input font file.
  84. ```
  85. The `FONT` argument is generally a TrueType Font file (TTF).
  86. The `OUTPUT` argument is the output image to generate, generally something like `my_font.png`.
  87. The `UNICODE_GLYPHS` argument allows for specifying extra unicode glyphs to generate, and accepts a string.
  88. **Examples**:
  89. ```
  90. $ qmk painter-make-font-image --font NotoSans-ExtraCondensedBold.ttf --size 11 -o noto11.png --unicode-glyphs "ĄȽɂɻɣɈʣ"
  91. ```
  92. ### `qmk painter-convert-font-image`
  93. This command converts an intermediate font image to the QFF File Format.
  94. This command expects an image that conforms to the following format:
  95. * Top-left pixel (at `0,0`) is the "delimiter" color:
  96. * Each glyph in the font starts when a pixel of this color is found on the first row
  97. * The first row is discarded when converting to the QFF format
  98. * The number of delimited glyphs must match the supplied arguments to the command:
  99. * The full ASCII set `0x20..0x7E` (if `--no-ascii` was not specified)
  100. * The corresponding number of unicode glyphs if any were specified with `--unicode-glyphs`
  101. * The order of the glyphs matches the ASCII set, if any, followed by the Unicode glyph set, if any.
  102. **Usage**:
  103. ```
  104. usage: qmk painter-convert-font-image [-h] [-r] -f FORMAT [-u UNICODE_GLYPHS] [-n] [-o OUTPUT] [-i INPUT]
  105. optional arguments:
  106. -h, --help show this help message and exit
  107. -r, --no-rle Disable the use of RLE to minimise converted image size.
  108. -f FORMAT, --format FORMAT
  109. Output format, valid types: pal256, pal16, pal4, pal2, mono256, mono16, mono4, mono2
  110. -u UNICODE_GLYPHS, --unicode-glyphs UNICODE_GLYPHS
  111. Also generate the specified unicode glyphs.
  112. -n, --no-ascii Disables output of the full ASCII character set (0x20..0x7E), exporting only the glyphs specified.
  113. -o OUTPUT, --output OUTPUT
  114. Specify output directory. Defaults to same directory as input.
  115. -i INPUT, --input INPUT
  116. Specify input graphic file.
  117. ```
  118. The same arguments for `--no-ascii` and `--unicode-glyphs` need to be specified, as per `qmk painter-make-font-image`.
  119. **Examples**:
  120. ```
  121. $ cd /home/qmk/qmk_firmware/keyboards/my_keeb
  122. $ qmk painter-convert-font-image --input noto11.png -f mono4 --unicode-glyphs "ĄȽɂɻɣɈʣ"
  123. Writing /home/qmk/qmk_firmware/keyboards/my_keeb/generated/noto11.qff.h...
  124. Writing /home/qmk/qmk_firmware/keyboards/my_keeb/generated/noto11.qff.c...
  125. ```
  126. ## Quantum Painter Drawing API :id=quantum-painter-api
  127. All APIs require a `painter_device_t` object as their first parameter -- this object comes from the specific device initialisation, and instructions on creating it can be found in each driver's respective section.
  128. To use any of the APIs, you need to include `qp.h`:
  129. ```c
  130. #include <qp.h>
  131. ```
  132. ### General Notes :id=quantum-painter-api-general
  133. The coordinate system used in Quantum Painter generally accepts `left`, `top`, `right`, and `bottom` instead of x/y/width/height, and each coordinate is inclusive of where pixels should be drawn. This is required as some datatypes used by display panels have a maximum value of `255` -- for any value or geometry extent that matches `256`, this would be represented as a `0`, instead.
  134. ?> Drawing a horizontal line 8 pixels long, starting from 4 pixels inside the left side of the display, will need `left=4`, `right=11`.
  135. All color data matches the standard QMK HSV triplet definitions:
  136. * Hue is of the range `0...255` and is internally mapped to 0...360 degrees.
  137. * Saturation is of the range `0...255` and is internally mapped to 0...100% saturation.
  138. * Value is of the range `0...255` and is internally mapped to 0...100% brightness.
  139. ?> Colors used in Quantum Painter are not subject to the RGB lighting CIE curve, if it is enabled.
  140. ### Device Control :id=quantum-painter-api-device-control
  141. #### Display Initialisation :id=quantum-painter-api-init
  142. ```c
  143. bool qp_init(painter_device_t device, painter_rotation_t rotation);
  144. ```
  145. The `qp_init` function is used to initialise a display device after it has been created. This accepts a rotation parameter (`QP_ROTATION_0`, `QP_ROTATION_90`, `QP_ROTATION_180`, `QP_ROTATION_270`), which makes sure that the orientation of what's drawn on the display is correct.
  146. ```c
  147. static painter_device_t display;
  148. void keyboard_post_init_kb(void) {
  149. display = qp_make_.......; // Create the display
  150. qp_init(display, QP_ROTATION_0); // Initialise the display
  151. }
  152. ```
  153. #### Display Power :id=quantum-painter-api-power
  154. ```c
  155. bool qp_power(painter_device_t device, bool power_on);
  156. ```
  157. The `qp_power` function instructs the display whether or not the display panel should be on or off.
  158. !> If there is a separate backlight controlled through the normal QMK backlight API, this is not controlled by the `qp_power` function and needs to be manually handled elsewhere.
  159. ```c
  160. static uint8_t last_backlight = 255;
  161. void suspend_power_down_user(void) {
  162. if (last_backlight == 255) {
  163. last_backlight = get_backlight_level();
  164. }
  165. backlight_set(0);
  166. rgb_matrix_set_suspend_state(true);
  167. qp_power(display, false);
  168. }
  169. void suspend_wakeup_init_user(void) {
  170. qp_power(display, true);
  171. rgb_matrix_set_suspend_state(false);
  172. if (last_backlight != 255) {
  173. backlight_set(last_backlight);
  174. }
  175. last_backlight = 255;
  176. }
  177. ```
  178. #### Display Clear :id=quantum-painter-api-clear
  179. ```c
  180. bool qp_clear(painter_device_t device);
  181. ```
  182. The `qp_clear` function clears the display's screen.
  183. #### Display Flush :id=quantum-painter-api-flush
  184. ```c
  185. bool qp_flush(painter_device_t device);
  186. ```
  187. The `qp_flush` function ensures that all drawing operations are "pushed" to the display. This should be done as the last operation whenever a sequence of draws occur, and guarantees that any changes are applied.
  188. !> Some display panels may seem to work even without a call to `qp_flush` -- this may be because the driver cannot queue drawing operations and needs to display them immediately when invoked. In general, calling `qp_flush` at the end is still considered "best practice".
  189. ```c
  190. void housekeeping_task_user(void) {
  191. static uint32_t last_draw = 0;
  192. if (timer_elapsed32(last_draw) > 33) { // Throttle to 30fps
  193. last_draw = timer_read32();
  194. // Draw a rect based off the current RGB color
  195. qp_rect(display, 0, 7, 0, 239, rgb_matrix_get_hue(), 255, 255);
  196. qp_flush(display);
  197. }
  198. }
  199. ```
  200. ### Drawing Primitives :id=quantum-painter-api-primitives
  201. #### Set Pixel :id=quantum-painter-api-setpixel
  202. ```c
  203. bool qp_setpixel(painter_device_t device, uint16_t x, uint16_t y, uint8_t hue, uint8_t sat, uint8_t val);
  204. ```
  205. The `qp_setpixel` can be used to set a specific pixel on the screen to the supplied color.
  206. ?> Using `qp_setpixel` for large amounts of drawing operations is inefficient and should be avoided unless they cannot be achieved with other drawing APIs.
  207. ```c
  208. void housekeeping_task_user(void) {
  209. static uint32_t last_draw = 0;
  210. if (timer_elapsed32(last_draw) > 33) { // Throttle to 30fps
  211. last_draw = timer_read32();
  212. // Draw a 240px high vertical rainbow line on X=0:
  213. for (int i = 0; i < 239; ++i) {
  214. qp_setpixel(display, 0, i, i, 255, 255);
  215. }
  216. qp_flush(display);
  217. }
  218. }
  219. ```
  220. #### Draw Line :id=quantum-painter-api-line
  221. ```c
  222. bool qp_line(painter_device_t device, uint16_t x0, uint16_t y0, uint16_t x1, uint16_t y1, uint8_t hue, uint8_t sat, uint8_t val);
  223. ```
  224. The `qp_line` can be used to draw lines on the screen with the supplied color.
  225. ```c
  226. void housekeeping_task_user(void) {
  227. static uint32_t last_draw = 0;
  228. if (timer_elapsed32(last_draw) > 33) { // Throttle to 30fps
  229. last_draw = timer_read32();
  230. // Draw 8px-wide rainbow down the left side of the display
  231. for (int i = 0; i < 239; ++i) {
  232. qp_line(display, 0, i, 7, i, i, 255, 255);
  233. }
  234. qp_flush(display);
  235. }
  236. }
  237. ```
  238. #### Draw Rect :id=quantum-painter-api-rect
  239. ```c
  240. bool qp_rect(painter_device_t device, uint16_t left, uint16_t top, uint16_t right, uint16_t bottom, uint8_t hue, uint8_t sat, uint8_t val, bool filled);
  241. ```
  242. The `qp_rect` can be used to draw rectangles on the screen with the supplied color, with or without a background fill. If not filled, any pixels inside the rectangle will be left as-is.
  243. ```c
  244. void housekeeping_task_user(void) {
  245. static uint32_t last_draw = 0;
  246. if (timer_elapsed32(last_draw) > 33) { // Throttle to 30fps
  247. last_draw = timer_read32();
  248. // Draw 8px-wide rainbow filled rectangles down the left side of the display
  249. for (int i = 0; i < 239; i+=8) {
  250. qp_rect(display, 0, i, 7, i+7, i, 255, 255, true);
  251. }
  252. qp_flush(display);
  253. }
  254. }
  255. ```
  256. #### Draw Circle :id=quantum-painter-api-circle
  257. ```c
  258. bool qp_circle(painter_device_t device, uint16_t x, uint16_t y, uint16_t radius, uint8_t hue, uint8_t sat, uint8_t val, bool filled);
  259. ```
  260. The `qp_circle` can be used to draw circles on the screen with the supplied color, with or without a background fill. If not filled, any pixels inside the circle will be left as-is.
  261. ```c
  262. void housekeeping_task_user(void) {
  263. static uint32_t last_draw = 0;
  264. if (timer_elapsed32(last_draw) > 33) { // Throttle to 30fps
  265. last_draw = timer_read32();
  266. // Draw r=4 filled circles down the left side of the display
  267. for (int i = 0; i < 239; i+=8) {
  268. qp_circle(display, 4, 4+i, 4, i, 255, 255, true);
  269. }
  270. qp_flush(display);
  271. }
  272. }
  273. ```
  274. #### Draw Ellipse :id=quantum-painter-api-ellipse
  275. ```c
  276. bool qp_ellipse(painter_device_t device, uint16_t x, uint16_t y, uint16_t sizex, uint16_t sizey, uint8_t hue, uint8_t sat, uint8_t val, bool filled);
  277. ```
  278. The `qp_ellipse` can be used to draw ellipses on the screen with the supplied color, with or without a background fill. If not filled, any pixels inside the ellipses will be left as-is.
  279. ```c
  280. void housekeeping_task_user(void) {
  281. static uint32_t last_draw = 0;
  282. if (timer_elapsed32(last_draw) > 33) { // Throttle to 30fps
  283. last_draw = timer_read32();
  284. // Draw 16x8 filled ellipses down the left side of the display
  285. for (int i = 0; i < 239; i+=8) {
  286. qp_ellipse(display, 8, 4+i, 16, 8, i, 255, 255, true);
  287. }
  288. qp_flush(display);
  289. }
  290. }
  291. ```
  292. ### Image Functions :id=quantum-painter-api-images
  293. #### Load Image :id=quantum-painter-api-load-image
  294. ```c
  295. painter_image_handle_t qp_load_image_mem(const void *buffer);
  296. ```
  297. The `qp_load_image_mem` function loads a QGF image from memory or flash.
  298. `qp_load_image_mem` returns a handle to the loaded image, which can then be used to draw to the screen using `qp_drawimage`, `qp_drawimage_recolor`, `qp_animate`, or `qp_animate_recolor`. If an image is no longer required, it can be unloaded by calling `qp_close_image` below.
  299. See the [CLI Commands](quantum_painter.md?id=quantum-painter-cli) for instructions on how to convert images to [QGF](quantum_painter_qgf.md).
  300. ?> The total number of images available to load at any one time is controlled by the configurable option `QUANTUM_PAINTER_NUM_IMAGES` in the table above. If more images are required, the number should be increased in `config.h`.
  301. Image information is available through accessing the handle:
  302. | Property | Accessor |
  303. |-------------|----------------------|
  304. | Width | `image->width` |
  305. | Height | `image->height` |
  306. | Frame Count | `image->frame_count` |
  307. #### Unload Image :id=quantum-painter-api-close-image
  308. ```c
  309. bool qp_close_image(painter_image_handle_t image);
  310. ```
  311. The `qp_close_image` function releases resources related to the loading of the supplied image.
  312. #### Draw image :id=quantum-painter-api-draw-image
  313. ```c
  314. bool qp_drawimage(painter_device_t device, uint16_t x, uint16_t y, painter_image_handle_t image);
  315. bool qp_drawimage_recolor(painter_device_t device, uint16_t x, uint16_t y, painter_image_handle_t image, uint8_t hue_fg, uint8_t sat_fg, uint8_t val_fg, uint8_t hue_bg, uint8_t sat_bg, uint8_t val_bg);
  316. ```
  317. The `qp_drawimage` and `qp_drawimage_recolor` functions draw the supplied image to the screen at the supplied location, with the latter function allowing for monochrome-based images to be recolored.
  318. ```c
  319. // Draw an image on the bottom-right of the 240x320 display on initialisation
  320. static painter_image_handle_t my_image;
  321. void keyboard_post_init_kb(void) {
  322. my_image = qp_load_image_mem(gfx_my_image);
  323. if (my_image != NULL) {
  324. qp_drawimage(display, (239 - my_image->width), (319 - my_image->height), my_image);
  325. }
  326. }
  327. ```
  328. #### Animate Image :id=quantum-painter-api-animate-image
  329. ```c
  330. deferred_token qp_animate(painter_device_t device, uint16_t x, uint16_t y, painter_image_handle_t image);
  331. deferred_token qp_animate_recolor(painter_device_t device, uint16_t x, uint16_t y, painter_image_handle_t image, uint8_t hue_fg, uint8_t sat_fg, uint8_t val_fg, uint8_t hue_bg, uint8_t sat_bg, uint8_t val_bg);
  332. ```
  333. The `qp_animate` and `qp_animate_recolor` functions draw the supplied image to the screen at the supplied location, with the latter function allowing for monochrome-based animations to be recolored. They also set up internal timing such that each frame is rendered at the correct time as per the animated image.
  334. Once an image has been set to animate, it will loop indefinitely until stopped, with no user intervention required.
  335. Both functions return a `deferred_token`, which can then be used to stop the animation, using `qp_stop_animation` below.
  336. ```c
  337. // Animate an image on the bottom-right of the 240x320 display on initialisation
  338. static painter_image_handle_t my_image;
  339. static deferred_token my_anim;
  340. void keyboard_post_init_kb(void) {
  341. my_image = qp_load_image_mem(gfx_my_image);
  342. if (my_image != NULL) {
  343. my_anim = qp_animate(display, (239 - my_image->width), (319 - my_image->height), my_image);
  344. }
  345. }
  346. ```
  347. #### Stop Animation :id=quantum-painter-api-stop-animation
  348. ```c
  349. void qp_stop_animation(deferred_token anim_token);
  350. ```
  351. The `qp_stop_animation` function stops the previously-started animation.
  352. ```c
  353. void housekeeping_task_user(void) {
  354. if (some_random_stop_reason) {
  355. qp_stop_animation(my_anim);
  356. }
  357. }
  358. ```
  359. ### Font Functions :id=quantum-painter-api-fonts
  360. #### Load Font :id=quantum-painter-api-load-font
  361. ```c
  362. painter_font_handle_t qp_load_font_mem(const void *buffer);
  363. ```
  364. The `qp_load_font_mem` function loads a QFF font from memory or flash.
  365. `qp_load_font_mem` returns a handle to the loaded font, which can then be measured using `qp_textwidth`, or drawn to the screen using `qp_drawtext`, or `qp_drawtext_recolor`. If a font is no longer required, it can be unloaded by calling `qp_close_font` below.
  366. See the [CLI Commands](quantum_painter.md?id=quantum-painter-cli) for instructions on how to convert TTF fonts to [QFF](quantum_painter_qff.md).
  367. ?> The total number of fonts available to load at any one time is controlled by the configurable option `QUANTUM_PAINTER_NUM_FONTS` in the table above. If more fonts are required, the number should be increased in `config.h`.
  368. Font information is available through accessing the handle:
  369. | Property | Accessor |
  370. |-------------|----------------------|
  371. | Line Height | `image->line_height` |
  372. #### Unload Font :id=quantum-painter-api-close-font
  373. ```c
  374. bool qp_close_font(painter_font_handle_t font);
  375. ```
  376. The `qp_close_font` function releases resources related to the loading of the supplied font.
  377. #### Measure Text :id=quantum-painter-api-textwidth
  378. ```c
  379. int16_t qp_textwidth(painter_font_handle_t font, const char *str);
  380. ```
  381. The `qp_textwidth` function allows measurement of how many pixels wide the supplied string would result in, for the given font.
  382. #### Draw Text :id=quantum-painter-api-drawtext
  383. ```c
  384. int16_t qp_drawtext(painter_device_t device, uint16_t x, uint16_t y, painter_font_handle_t font, const char *str);
  385. int16_t qp_drawtext_recolor(painter_device_t device, uint16_t x, uint16_t y, painter_font_handle_t font, const char *str, uint8_t hue_fg, uint8_t sat_fg, uint8_t val_fg, uint8_t hue_bg, uint8_t sat_bg, uint8_t val_bg);
  386. ```
  387. The `qp_drawtext` and `qp_drawtext_recolor` functions draw the supplied string to the screen at the given location using the font supplied, with the latter function allowing for monochrome-based fonts to be recolored.
  388. ```c
  389. // Draw a text message on the bottom-right of the 240x320 display on initialisation
  390. static painter_font_handle_t my_font;
  391. void keyboard_post_init_kb(void) {
  392. my_font = qp_load_font_mem(font_opensans);
  393. if (my_font != NULL) {
  394. static const char *text = "Hello from QMK!";
  395. int16_t width = qp_textwidth(my_font, text);
  396. qp_drawtext(display, (239 - width), (319 - my_font->line_height), my_font, text);
  397. }
  398. }
  399. ```
  400. ### Advanced Functions :id=quantum-painter-api-advanced
  401. #### Get Geometry :id=quantum-painter-api-get-geometry
  402. ```c
  403. void qp_get_geometry(painter_device_t device, uint16_t *width, uint16_t *height, painter_rotation_t *rotation, uint16_t *offset_x, uint16_t *offset_y);
  404. ```
  405. The `qp_get_geometry` function allows external code to retrieve the current width, height, rotation, and drawing offsets.
  406. #### Set Viewport Offsets :id=quantum-painter-api-set-viewport
  407. ```c
  408. void qp_set_viewport_offsets(painter_device_t device, uint16_t offset_x, uint16_t offset_y);
  409. ```
  410. The `qp_set_viewport_offsets` function can be used to offset all subsequent drawing operations. For example, if a display controller is internally 240x320, but the display panel is 240x240 and has a Y offset of 80 pixels, you could invoke `qp_set_viewport_offsets(display, 0, 80);` and the drawing positioning would be corrected.
  411. #### Set Viewport :id=quantum-painter-api-viewport
  412. ```c
  413. bool qp_viewport(painter_device_t device, uint16_t left, uint16_t top, uint16_t right, uint16_t bottom);
  414. ```
  415. The `qp_viewport` function controls where raw pixel data is written to.
  416. #### Stream Pixel Data :id=quantum-painter-api-pixdata
  417. ```c
  418. bool qp_pixdata(painter_device_t device, const void *pixel_data, uint32_t native_pixel_count);
  419. ```
  420. The `qp_pixdata` function allows raw pixel data to be streamed to the display. It requires a native pixel count rather than the number of bytes to transfer, to ensure display panel data alignment is respected. E.g. for display panels using RGB565 internal format, sending 10 pixels will result in 20 bytes of transfer.
  421. !> Under normal circumstances, users will not need to manually call either `qp_viewport` or `qp_pixdata`. These allow for writing of raw pixel information, in the display panel's native format, to the area defined by the viewport.
  422. ## Quantum Painter Display Drivers :id=quantum-painter-drivers
  423. ### Common: Standard TFT (SPI + D/C + RST)
  424. Most TFT display panels use a 5-pin interface -- SPI SCK, SPI MOSI, SPI CS, D/C, and RST pins.
  425. For these displays, QMK's `spi_master` must already be correctly configured for the platform you're building for.
  426. The pin assignments for SPI CS, D/C, and RST are specified during device construction.
  427. ### GC9A01 :id=qp-driver-gc9a01
  428. Enabling support for the GC9A01 in Quantum Painter is done by adding the following to `rules.mk`:
  429. ```make
  430. QUANTUM_PAINTER_ENABLE = yes
  431. QUANTUM_PAINTER_DRIVERS = gc9a01_spi
  432. ```
  433. Creating a GC9A01 device in firmware can then be done with the following API:
  434. ```c
  435. painter_device_t qp_gc9a01_make_spi_device(uint16_t panel_width, uint16_t panel_height, pin_t chip_select_pin, pin_t dc_pin, pin_t reset_pin, uint16_t spi_divisor, int spi_mode);
  436. ```
  437. The device handle returned from the `qp_gc9a01_make_spi_device` function can be used to perform all other drawing operations.
  438. The maximum number of displays can be configured by changing the following in your `config.h` (default is 1):
  439. ```c
  440. // 3 displays:
  441. #define GC9A01_NUM_DEVICES 3
  442. ```
  443. ### ILI9163 :id=qp-driver-ili9163
  444. Enabling support for the ILI9163 in Quantum Painter is done by adding the following to `rules.mk`:
  445. ```make
  446. QUANTUM_PAINTER_ENABLE = yes
  447. QUANTUM_PAINTER_DRIVERS = ili9163_spi
  448. ```
  449. Creating a ILI9163 device in firmware can then be done with the following API:
  450. ```c
  451. painter_device_t qp_ili9163_make_spi_device(uint16_t panel_width, uint16_t panel_height, pin_t chip_select_pin, pin_t dc_pin, pin_t reset_pin, uint16_t spi_divisor, int spi_mode);
  452. ```
  453. The device handle returned from the `qp_ili9163_make_spi_device` function can be used to perform all other drawing operations.
  454. The maximum number of displays can be configured by changing the following in your `config.h` (default is 1):
  455. ```c
  456. // 3 displays:
  457. #define ILI9163_NUM_DEVICES 3
  458. ```
  459. ### ILI9341 :id=qp-driver-ili9341
  460. Enabling support for the ILI9341 in Quantum Painter is done by adding the following to `rules.mk`:
  461. ```make
  462. QUANTUM_PAINTER_ENABLE = yes
  463. QUANTUM_PAINTER_DRIVERS = ili9341_spi
  464. ```
  465. Creating a ILI9341 device in firmware can then be done with the following API:
  466. ```c
  467. painter_device_t qp_ili9341_make_spi_device(uint16_t panel_width, uint16_t panel_height, pin_t chip_select_pin, pin_t dc_pin, pin_t reset_pin, uint16_t spi_divisor, int spi_mode);
  468. ```
  469. The device handle returned from the `qp_ili9341_make_spi_device` function can be used to perform all other drawing operations.
  470. The maximum number of displays can be configured by changing the following in your `config.h` (default is 1):
  471. ```c
  472. // 3 displays:
  473. #define ILI9341_NUM_DEVICES 3
  474. ```
  475. ### SSD1351 :id=qp-driver-ssd1351
  476. Enabling support for the SSD1351 in Quantum Painter is done by adding the following to `rules.mk`:
  477. ```make
  478. QUANTUM_PAINTER_ENABLE = yes
  479. QUANTUM_PAINTER_DRIVERS = ssd1351_spi
  480. ```
  481. Creating a SSD1351 device in firmware can then be done with the following API:
  482. ```c
  483. painter_device_t qp_ssd1351_make_spi_device(uint16_t panel_width, uint16_t panel_height, pin_t chip_select_pin, pin_t dc_pin, pin_t reset_pin, uint16_t spi_divisor, int spi_mode);
  484. ```
  485. The device handle returned from the `qp_ssd1351_make_spi_device` function can be used to perform all other drawing operations.
  486. The maximum number of displays can be configured by changing the following in your `config.h` (default is 1):
  487. ```c
  488. // 3 displays:
  489. #define SSD1351_NUM_DEVICES 3
  490. ```
  491. ### ST7789 :id=qp-driver-st7789
  492. Enabling support for the ST7789 in Quantum Painter is done by adding the following to `rules.mk`:
  493. ```make
  494. QUANTUM_PAINTER_ENABLE = yes
  495. QUANTUM_PAINTER_DRIVERS = st7789_spi
  496. ```
  497. Creating a ST7789 device in firmware can then be done with the following API:
  498. ```c
  499. painter_device_t qp_st7789_make_spi_device(uint16_t panel_width, uint16_t panel_height, pin_t chip_select_pin, pin_t dc_pin, pin_t reset_pin, uint16_t spi_divisor, int spi_mode);
  500. ```
  501. The device handle returned from the `qp_st7789_make_spi_device` function can be used to perform all other drawing operations.
  502. The maximum number of displays can be configured by changing the following in your `config.h` (default is 1):
  503. ```c
  504. // 3 displays:
  505. #define ST7789_NUM_DEVICES 3
  506. ```
  507. !> Some ST7789 devices are known to have different drawing offsets -- despite being a 240x320 pixel display controller internally, some display panels are only 240x240, or smaller. These may require an offset to be applied; see `qp_set_viewport_offsets` above for information on how to override the offsets if they aren't correctly rendered.