Is there a good tool for generating STM32 Baremetal GUIs? - Page 1
Forum section: electronics / general

author: BlueEagle
author_rank: Newbie
timestamp: September 05, 2023, 04:50:57 pm
content: I have a STM32 project that uses the LTDC and custom graphics drivers to draw text, images, shapes, etc.It all works, and I've been making GUIs this way for years but it takes FOREVER to make the GUI look good. Everything has to be carefully arranged by the pixel, and text has to be manually erased and redrawn from the buffers all the time, among other issues.I would really like to use a graphical GUI editor so I can quickly draw up screens with buttons, images, sliders, and all that. I've been trying to set up TouchGFX, but it's been like pulling teeth.My projects are almost entirely custom baremetal code so ideally I could just generate some graphics code and copy and paste it into my project. I don't really want to add a bunch of bloat in the form of libraries if possible.Do any of you guys have a toolchain that works well for this?

author: hansd
author_rank: Contributor
timestamp: September 06, 2023, 12:17:41 am
content: Have a look at LVGL.

author: BlueEagle
author_rank: Newbie
timestamp: September 06, 2023, 01:38:35 am
content: Quote from: hansd on September 06, 2023, 12:17:41 amLVGL looks perfect, but I hate that the designer is a subscription service.

author: hansd
author_rank: Contributor
timestamp: September 06, 2023, 04:20:30 am
content: Somewhere they have to make some moneyYou don't have to use the designer. You can do it by designing it on the PC with the simulator using the library and then port it to your board. All free of charge.

author: westfw
author_rank: Super Contributor
timestamp: September 06, 2023, 06:56:19 am
content: QuoteGUIs are like the #1 cause of program bloat, aren't they? Before you know it you have options to support 3D-transparent buttons with localization in at least a dozen languages and fonts. :-(

author: wek
author_rank: Frequent Contributor
timestamp: September 06, 2023, 07:50:06 am
content: I was about to recommend LVGL too, but then I realized exactly this -@BlueEagleis obviously after the designing part of the whole thing. Sure, the library itself solves a ton of headaches, that's why I'm using it, too; but the pixel-counting, searching-manual-for-the-right-function-or-symbol etc. processes are too familiar to me, too, to understand what pain it can be.There's probably no good solution. The whole bundle is too expensive to be free, you'll pay it somewhere that's 1. And should the bundle be attractive to masses in order to split the cost somehow, it inevitably imposes a "modern feel and look" upon you together with whatever convenience choices there are for the authors, which you have to accomodate to. TouchGFX is paid through the cost of the chips, which may sound "free" enough; but it suffers from 2 (C++, imposing a certain workflow and general bloat is that developer-convenience you have to suffer).Back in the days of simpler dot-matrix displays, I concocted myself a tool, which on PC looked like the late PaintBrush, and through UART connection to target it drew on the target display. Lot of effort, but spared me even more effort with the pixel-shifting on target etc. I even simulated the font generator for targets with T6963. And I supported copy/paste through standard windows clipboard (which was a PITA of its own kind, due to microsoftoisms). Kinda similar to the "can simulate on PC" approach, except that pictures on those displays looked very differently than on PC monitor.A couple of years ago, in ages of STM32 and LVGL and TFT, I tried to write a tool which run on the same target and allowed to visualize and manipulate the internal LVGL structures through a menu system written in the same LVGL... much like a visual designer, but on the target. I failed miserably, the thing was complex, rigid and cumbersome... So, maybe something like that could be split off to PC, a tool which would connect to target, read out the LVGL structures, visualizing them in a tree or other suitable form, and allowing to manipulate its values... it won't need to be fancy, all it takes is a way to click through a tree and enter numberic values. It does not need to visualize the result - it's visualized automagically on the target upon sending the changes and redraw. However, that's still a huge task which would require modification of LVGL itself (read: irreversibly forking from the official sources with all the consequences) and in no way would pay off as an internal project.But, if your display system is simple enough (I presume, tile-based), this may be the way to go.JW

author: JPortici
author_rank: Super Contributor
timestamp: September 06, 2023, 09:16:30 am
content: Quote from: BlueEagle on September 06, 2023, 01:38:35 amI feel your pain, but at least it's only the designer. It's not *that* hard to make simple but effective layouts by hand.Library is free, open source and very powerful, look and feel from this century, can use it on any target with enough ram, even on PC. Simulator is free and works. If you ask me that's miles ahead any other graphic library (Qt would be even better but it has very few targets and you don't want to know how much it costs)EDIT: I see they added a perpetual free license for personal use, cool! And perpetual licenses for business. They weren't there a few months ago when i first saw they released the editor

author: BlueEagle
author_rank: Newbie
timestamp: September 06, 2023, 01:29:52 pm
content: Quote from: wek on September 06, 2023, 07:50:06 amYou know, I think you might be on to something with that. Maybe something quick and dirty, like making the positions statics and using the debugger to edit values until everything looks ok.

author: ajb
author_rank: Super Contributor
timestamp: September 06, 2023, 06:01:22 pm
content: You could also go the other direction: If you've already got a set of low-level draw functions targeting an internal framebuffer, then (as long as you're not relying on ST's dedicated graphics peripherals) you could build that to run on a PC and directly display the resulting output. From there you could similarly use a debugger to tweak and redraw, or ingest key values from a text file and update live, or go all the way and implement some sort of interactive editing.On the other hand, if you're spending a lot of time on pixel-by-pixel alignment of primitives, it may be worth spending more time building up more sophisticated graphic functions/objects that handle the pixel math internally. Something like a button is pretty obvious in that regard, but list/grid layouts, or even basic templating wouldn't be too hard to create and could have a significant return on the time investment. Yes, this is technically more overhead and could be considered 'bloat', but consider that your time is generally much more valuable than the CPU's time, so trading off some of the latter for more of the former is usually a good bargain. All depends on what aspects are currently bogging you down.

author: westfw
author_rank: Super Contributor
timestamp: September 06, 2023, 06:55:29 pm
content: Do any of the phone app builders generate high-level descriptions that could be parsed/compiled into C code using your graphics libraries?It's been a while since I've tried to program a phone, and the churn rate is extraordinary, but I seem to recall that screen layouts and etc end up as some sort of 'resource' file rather than actual "code."

author: zapta
author_rank: Super Contributor
timestamp: September 10, 2023, 11:37:22 pm
content: Quote from: BlueEagle on September 06, 2023, 01:38:35 amYou don't have to use the designer. The designer is relatively new and people used LCGL for years without a designer.

author: Scrts
author_rank: Frequent Contributor
timestamp: September 11, 2023, 12:27:45 pm
content: Did you see TouchGFX? It says it's free.https://www.st.com/en/embedded-software/x-cube-touchgfx.htmlhttps://www.st.com/en/development-tools/touchgfxdesigner.htmlhttps://support.touchgfx.com/docs/introduction/welcomeAnother to consider:https://www.embedded-wizard.de/platforms/stmicroelectronics

author: AVI-crak
author_rank: Regular Contributor
timestamp: September 11, 2023, 01:44:08 pm
content: Writing your own library is surprisingly simple.First you need primitives - point, line, curve, binary rectangle for graphics.Then you need to write interface primitives - text area, colour area, picture.A layer of logic is written on all this ugliness. These are simple algorithms, each one individually fits into a couple of lines.The topmost layer is the user interface. These are those functions and structures that are visible when you connect the library to the project.It's simple, you can write it or use someone else's.

author: DavidAlfa
author_rank: Super Contributor
timestamp: September 11, 2023, 02:35:47 pm
content: AVI-crack, we all know how to use primitives, but designing a GUI manually is very tedious and slow.He's asking for a WYSIWYG editor, were you make your design and it translates then into those primitives.Alternatively, using existing DWIN / Nextion devices might be cost-effective.You have the editor and the LCD module doing the heavy work, the mcu only need to tell the module "show this menu", "Show this value there", etc.

author: ali_asadzadeh
author_rank: Super Contributor
timestamp: September 12, 2023, 08:08:54 am
content: Just googling, and found thishttps://github.com/CURTLab/LVGLBuilder, it's a free WYSIWYG editor for LVGL

author: Ario
author_rank: Regular Contributor
timestamp: September 12, 2023, 08:12:28 am
content: I use EmWin from segger, if you use a nxp chip you may use emWin for free. Alternatively if you use it for non-commercial purposes it is also free I think.

author: BlueEagle
author_rank: Newbie
timestamp: September 12, 2023, 02:44:48 pm
content: Quote from: Ario on September 12, 2023, 08:12:28 amWow, 15k USD for a license. Maybe next time I'll consider using a nxp chip, but that ship has sailed on this project. Thanks for the suggestion.

author: DavidAlfa
author_rank: Super Contributor
timestamp: September 12, 2023, 02:52:27 pm
content: Also free for stm32!https://www.st.com/en/embedded-software/stemwin.html

author: peter-h
author_rank: Super Contributor
timestamp: September 13, 2023, 06:44:58 am
content: This is interesting. I started looking at this a while ago:https://www.eevblog.com/forum/projects/small-tft-display-5x5cm-for-moving-graphics-over-spi/and got to this:https://www.ramtex.dk/display-controller-driver/rgb/st7789.htmThat gives you fairly low level stuff like drawing polygons, text, etc, and it keeps track of object overlap which is quite tedious to do manually (it is usually not feasible to just redraw the whole display, due to the large amount of data, especially over SPI). The trick with this $500 library is matching the display controller it supports with the display(s) you want to use, otherwise you end up buying multiple $500 licenses. But I found a good match which covers displays up to almost VGA size.There is a lot of open source code for driving specific controllers and setting a pixel or even drawing a line (Bresenham), but one needs much more than that in most cases.What I wonder is where LVGL comes in. I can see you can construct the page, a bit like VC++ has an editor where you can drag/drop GUI objects like radio buttons onto a form. But does it support a wide range of graphics controllers directly? It statesTo make your display work with LVGL all you need is a function which can copy the rendered image to the display. If you have it you can integrate LVGL in 10 minutes.which sounds like you need to write the controller dependent code - either copy pixels or maybe a rectangle, or a polygon? So you probably want the above Ramtex library as well, or spend some days or weeks writing that code.That ST lib mentioned above probably has a huge learning curve, looking at what else ST do. I've been up the Cube IDE + LWIP + FreeRTOS + etc curve. Be prepared for structs of structs of structs and thousands of lines of definitions and typedefs and macros of typedefs of macrosI don't think you can get way from "pixel counting" if you want a really slick looking product - unless your display is huge

author: jan28
author_rank: Contributor
timestamp: September 13, 2023, 09:49:32 am
content: I've been using EEZ-Studio to generate UI and most of the UI interaction (dynamically enable/disable buttons, switch pages, ...) for a project. It is LVGL compatible.https://www.envox.eu/studio/studio-introduction/It's open-source and the current version is pretty feature complete for touch displays. Documentation is getting there now, but it might have a learning curve because it is not juist UI element placement but also low-code with links to native code. I like this mix.On this forum:https://www.eevblog.com/forum/testgear/eez-studio-for-accessing-your-(scpi)-instruments/but not very active. Discord is more active.Disclaimer: I'm an active member of the community.

author: hansd
author_rank: Contributor
timestamp: September 13, 2023, 11:12:02 am
content: "What I wonder is where LVGL comes in. I can see you can construct the page, a bit like VC++ has an editor where you can drag/drop GUI objects like radio buttons onto a form. But does it support a wide range of graphics controllers directly?"LVGL is a widget library (buttons, sliders, text boxes etc) build up from primitives and sits on top of the display driver.It needs a memory buffer for drawing and your application handles the transfer to the display. Development can be done in C or other ports like Python etc.

author: BlueEagle
author_rank: Newbie
timestamp: September 13, 2023, 01:09:55 pm
content: I stopped trying to set up TouchGFX, and started on LVGL. Setting it up isso mucheasier. It only took me about a day to get some test graphics displaying. Haven't tried the WYSIWYG editor yet though.

author: AVI-crak
author_rank: Regular Contributor
timestamp: September 13, 2023, 02:30:39 pm
content: I agree, LVGL is simple and affordable.All graphics libraries are exorbitantly fat, LVGL is no exception. However, LVGL can be significantly reduced in size without headaches. It is almost impossible to do the same with other libraries. The reason is the huge number of cross-links.

author: JPortici
author_rank: Super Contributor
timestamp: September 13, 2023, 02:48:35 pm
content: Quote from: peter-h on September 13, 2023, 06:44:58 amhttps://docs.lvgl.io/8.3/overview/renderers/index.htmlThere are a couple of integrated controllers there. (Even though there are not docs in the site, they are actually supported in the source code)But if with "controller" you meen a LCD driver IC, in most cases the only thing to do is to shove pixels, and that's always up to you (parallel, spi, i2c, interrupt based, dma based, ...)

author: peter-h
author_rank: Super Contributor
timestamp: September 14, 2023, 10:58:53 am
content: From the above URL:Renderers and GPUsSoftware rendererSDL rendererArm-2D GPUHow to UseDesign ConsiderationsExamplesNXP PXP and VGLite GPUDMA2D GPUI don't see any LCD controllers there, like Ramtex support:ST7789 TFT display driver libraryThe ST7789, ST7789C, ST7789V, ST7789V2, ST7789V3, ST7789VI, ST7789H2, and ST7789VW display controllers are supported by the RAMTEX S6D0129 display driver library package.The devil is in the detail. I guess some arm32 CPUs, connected to an LCD via a 16 bit or 32 bit bus, can do this fairly efficiently using built-in hardware features, but if the LCD is SPI-connected, none of these can be used, and the amount of data which needs to be transferred is critical. The ramtex library seems to be able to optimise that.I will take a look at this when I get to that stage of the project, and will report.

author: JPortici
author_rank: Super Contributor
timestamp: September 14, 2023, 02:37:16 pm
content: Quote from: peter-h on September 14, 2023, 10:58:53 amYeah, that happens AFTER the screen render (which is either the software rendered, or accelerated by the GPU). Talking to the TFT controllers, that is the "shoving pixel out of the MCU" part, because almost all TFT controllers are pretty dumb in the end, or it doesn't make sense to render some parts in software and some in the controller, software would get too complicated too quickly. IIRC you can setup LVGL to only udpate the pixels that will change, instead of redrawing the entire buffer. I think there is also a mode in which you don't use the internal memory, but write the pixel as soon as it's calculated. Combine the two and you should have what the ramtex library does

author: peter-h
author_rank: Super Contributor
timestamp: September 14, 2023, 03:32:45 pm
content: OK.However any one pixel at a time drawing will be painfully slow, even at the max SPI clock of most LCDs (I can run at 21MHz but most displays can't). This is largely due to the address etc bytes.Yes using SPI is really desirable otherwise the LCD eats up most of your GPIOI think, ideally, one would transfer a rectangle using SPI, or some sequence of adjacent pixels.

author: m98
author_rank: Frequent Contributor
timestamp: September 14, 2023, 05:02:44 pm
content: I found this tool from NXP:https://www.nxp.com/design/software/development-software/gui-guider:GUI-GUIDERWhich looks a lot better than Squareline Studio for LVGL, as it includes all LVGL widgets and also supports Lottie animations. Only thing I haven't tried yet is exporting the code, but LVGL gui code is not hardware or RTOS specific, so it should work with non-NXP microcontrollers just fine.

author: dietert1
author_rank: Super Contributor
timestamp: February 26, 2024, 10:36:07 pm
content: Recently i spent two days to work out font generation for a MSP3520 TFT display connected to a STM32L476 via SPI.I printed the set of characters i wanted to use in Paintshop Pro with Verdana 24 in one line of text in black and white and saved the file. Then i used a small tool named "ImageConverter565.exe" supplied by a chinese trader of those displays. It converts the graphics into a C header file. Then i wrote my own tool to analyze that data block in order to convert the graphics from 16 bit color to 1 bit per pixel and find the horizontal locations of the characters. Also i added a constant C string that serves as index to pick the right character from the image. The result gets dumped into a new header file ready to include into the MCU project. Then there is a small procedure to print one character using kind of bitblt and procedures to print text using , and . separators as tabs.I also wrote some procedures to draw rectangles. Need to enhance that for rounded rectangles. I mean it is pretty easy to arrive at some basic GUI elements.Another problem i solved before is running the TFT controller and the touch controller on the same SPI bus. As far as i remember there was a problem with three-stating the ILI4988 output. And the touch controller uses its 3.3 V supply as voltage reference and there was a pretty weak LDO common to the display and the touch controller.Regards, Dieter

author: uer166
author_rank: Super Contributor
timestamp: February 26, 2024, 10:58:12 pm
content: FIY Gimp can output C headers natively. It's what I use for my graphics projects as direct drop-ins for bitmaps.

author: SiliconWizard
author_rank: Super Contributor
timestamp: February 26, 2024, 11:12:55 pm
content: I use LCD Image Converter, which is a great tool. Very flexible, can generate all kinds of pixel formats (and customizable too), converts bitmaps as well as fonts.https://lcd-image-converter.riuson.com

author: Nominal Animal
author_rank: Super Contributor
timestamp: February 27, 2024, 09:58:27 am
content: I useNetPBMformats for custom image processing almost every day.The P1 (ASCII bitmap), P2 (ASCII grayscale), and P3 (ASCII rgb) formats are plain text, so in a pinch one can use those.I prefer P4, P5, and P6 formats, where the header is plain text, but the pixel data is in binary.The PF (using a 32-bit Binary32floatfor each RGB component per pixel) can be useful for very-HDR stuff.GIMP can load and save in these formats (.pbm,.pgm,.ppm,.pfmfile extensions, respectively), and of course, the NetPBM tools themselves can convert these to GIF, PNG, JPEG, BMP, AutoCAD (database or slide), XPM, and a number of other formats. The NetPBM tools include utilities likepnmcat, which can concatenate a number of NetPBM images into a single image, andpnmflip, that can mirror and transpose the images into other orientations.From C, parsing the header correctly for the binary versions is slightly funny, and most people do it "wrong". You're actually supposed to read the two firstchars of the file, that tell the file format. Then, you should use a function (like agetnni()I wrote a decade ago), that reads a non-negative integer, skippingleading whitespace and comments, for each of the header fields. After the last header field, there will be exactly one ASCII whitespacechar(\t,\n,\v,\f,\r, or space). The binary data will follow. For PGM and PPM formats, if the componentmaxvalis between 255 and 65535, inclusive, the component uses two bytes; otherwise one byte only. (The maxval can be any positive value up to 65535, and corresponds to 100% of that component.)In Python, it is extremely simple to process in a similar manner, although again, most people do it "wrong", assuming the header is a fixed number of "lines".For widgets, one can consider using 2D vector primitives, using an existing rasterizer or creating their own, and test it in practice on a fully-hosted system by creating canvases for the widgets (or the entire display), and saving the display images as PPM for viewing. No need to futz with GUI toolkits, very quick to do in plain C; I can do it in Linux even in freestanding C (without the standard library, using only one inline assembly helper forwrite()syscalls to standard output for generating the image; it is arch-specific, though).For widgets you use your own compression algorithms, say 16-color palettes (32/48 bytes of palette per widget or widget set, then two pixels per byte; doubling the palette size in RAM allows you extremely rapid RGB/YCbCr/YUV/whatever lookup). Thepnmquantisn't the best color quantizer (for picking the palette from a PNM image or multiple imagespnmcat'd together), and I've intended to create a replacement that uses the relatively new OKLab color model for computing the color differences (ΔE) used for grouping, assuming RGB data uses the sRGB color space (as used on the web, for example). The colormap format is just a PPM image with one pixel per color to be used, so trivial too.One could even create a simple web page (no network connection needed, everything in a single HTML file) using JavaScript and Canvas to render fonts into a display buffer (seeHTML Canvas DOM object), and generate per-glyph bitmap definitions in C for one to copy-paste to a text file, and even demonstrate how a sequence of the bitmap glyphs would look like. Such HTML pages cannot really read or write local files; that's their only major limitation.I cry for those who believe BMP is the easiest image format to manipulate from your own scripts/programs.

author: wek
author_rank: Frequent Contributor
timestamp: February 27, 2024, 12:42:27 pm
content: > From C, parsing the header correctly for the binary versions is slightly funny,As long as single-use single-purpose homebrew tools to convert bitmaps into whatever my target needs are concerned, I never could care enough to do it *properly*: it's simpler to learn how to coax the "big" drawing programs to output consistently files where the binary which matters is always at the same place and in the same format. Even if it means to use always the same size canvas, and crop it in my tool.Some "big" programs can output bare binaries (which is IMO better than C sources/headers/whatever).JW

author: Nominal Animal
author_rank: Super Contributor
timestamp: February 27, 2024, 04:12:59 pm
content: Quote from: wek on February 27, 2024, 12:42:27 pmThat's exactly what P5 (PGM), P6 (PPM), and PF and Pf (PFM) format NetPBM files are, if you look at the file after the header.Even Adobe Photoshop supports these, and that's as "big" as you can get for professional image editing.In Augmented Backus–Naur format, I do believe the binary formats' headers (with binary data immediately following) can be correctly described asPBM = "P" "4" sep WIDTH sep HEIGHT wscharPGM = "P" "5" sep WIDTH sep HEIGHT sep MAXVAL wscharPPM = "P" "6" sep WIDTH sep HEIGHT sep MAXVAL wscharPFM = "P" "F" sep WIDTH sep HEIGHT sep RANGE LFPfM = "P" "f" sep WIDTH sep HEIGHT sep RANGE LFPFM4 = "P" "F" "4" sep WIDTH sep HEIGHT sep RANGE LFWIDTH = nonzero *digit ;ASCII positive decimal numberHEIGHT = nonzero *digit ;ASCII positive decimal numberMAXVAL = nonzero *digit ;ASCII positive decimal number between 1 and 65535, inclusiveRANGE = 1*( "-" / "+" ) ( 1*digit / 1*digit "." *digit / *digit "." 1*digit )nonzero = "1" / "2" / "3" / "4" / "5" / "6" / "7" / "8" / "9"digit = "0" / nonzerowschar = HTAB / LF / VTAB / FF / CR / " "sep = 1*(1*wschar / comment)comment = "#" *(anything except CR or LF)As you can see, it is easy to do it right by reading positive (nonzero) decimal numbers skipping the initial whitespace-and-comments (sep).PBM files have one bit per pixel, 0=white, 1=black. Rows are specified from top to bottom: top left pixel is the first, followed by the pixel to its right. If WIDTH is not a multiple of 8, each row is padded to a multiple of 8, so each row consists of Ceil(WIDTH/8) bytes. Each byte specifies eight pixels, with the most significant bit leftmost, and least significant bit rightmost.PGM files have one (MAXVAL < 256) or two (MAXVAL >= 256) bytes per pixel. Standard byte order is big-endian, but some do use little-endian. A value of 0 corresponds to black, and MAXVAL corresponding to white. Top left pixel is the first, followed by the pixel to its right.PPM files have three (MAXVAL < 256) or six (MAXVAL >= 256) bytes per pixel. This is like in PGM, except in triplets, first one corresponding to red, second to green, and third to blue. 0 is 0%, and MAXVAL is 100% of that component. Top left pixel is the first, followed by the pixel to its right.PFM files consist of three IEEE 754 Binary32floats per pixel, for red, green, and blue triplets. If RANGE is negative, the byte order is little-endian, and 0% corresponds to 0.0f and 100% corresponds to -RANGE. If RANGE is positive, the byte order is big-endian, and 0% corresponds to 0.0f and 100% to RANGE. Bottom left pixel is the first, followed by the pixel to its right.PfM files consist of one IEEE 754 Binary32floats per pixel, corresponding to grayscale, 0 corresponding to black. If RANGE is negative, the byte order is little-endian, and -RANGE corresponds to white. If RANGE is positive, the byte order is big-endian, and RANGE corresponds to white. Bottom left pixel is the first, followed by the pixel to its right.PFM4 files consist of four IEEE 754 Binary32floats per pixel, for red, green, blue, and alpha/opacity. If RANGE is negative, the byte order is little-endian, and 0% corresponds to 0.0f and 100% corresponds to -RANGE. If RANGE is positive, the byte order is big-endian, and 0% corresponds to 0.0f and 100% to RANGE. Bottom left pixel is the first, followed by the pixel to its right. This is not a widely supported format.There is also a P7 aka PAM format, but it is not widely supported.I tend to generate 8-bit PPM files using the sRGB colorspace, and they tend to open in all image editors from GIMP to Photoshop, but usually I use a chain of command-line tools to compress and optimize them into small PNG files (using a 16-256 color palette for minimal size).For vector stuff, I use SVG (typicallySVG 1.1). It isridiculouslysimple to generate, but not fun to rasterize. You simply emit<?xml version="1.0" encoding="UTF-8" standalone="no"?><svg xmlns="http://www.w3.org/2000/svg" version="1.1" viewBox="0 0widthheight"><path d="path-data" fill="fill" stroke="stroke" stroke-width="thickness" />...</svg>wherepath-dataconsists of single-letter commands followed by numeric parameters (typically coordinates),widthandheightdefine the visible range of the maximumxandycoordinates,fillandstrokeare eithernoneor an RGB color (using hexadecimal notation,#RGB,#RRGGBB). There are more options, of course, but this is usually sufficient for a lot of stuff.The...indicates other elements drawn on top. Mostly I usepaths,rects (to fill background; it defaults to transparent), andcircleelements (for dots and such).Quote from: wek on February 27, 2024, 12:42:27 pmI have a header file somewhere that uses<stdlib.h>and<stdio.h>and defines accessor functions to load and save 32 bit canvases (R8:G8:B8, R8:G8:B8:A8 with a separate PGM alpha channel, or R10:G10:B10) where each pixel corresponds to anuint32_t, and the fast getpixel()/setpixel() have bounds checking. I've also got fast 64-bit (for x86-64) RGB blending routines, although the quality of the result is nowhere near as nice if one used e.g. OKLab for the representation.Point is, it is a perfect format to use in ELF-based toolchains to import pixmap data in customized formats. You can use C, Python, or whatever your favourite language is on the host to convert the image format to whatever happens to be the optimal format for a specific use case on a microcontroller or embedded device. No added library dependencies. If you do decide to depend on the netpbm tools, you can then convert basically from and to any image format. If your compression/optimization code on the host also emits the final versions as PPM, they can be converted to PNG losslessly and included in the generated documentation, for visual verification.