Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add support for decoding XBM and XPM #2410

Open
mstoeckl opened this issue Jan 30, 2025 · 0 comments
Open

Add support for decoding XBM and XPM #2410

mstoeckl opened this issue Jan 30, 2025 · 0 comments

Comments

@mstoeckl
Copy link

mstoeckl commented Jan 30, 2025

XBM and XPM are two obsolete image formats that were used by the X window system.

It would be nice if image were able to decode them, because some image viewer programs indirectly use image, among them GNOME's Loupe. I happen to have 29 XPM and 88 XBM images scattered through /usr.

Edit: XBM file frequency statistics, if you are interested.

I wrote a script to count file endings for various image formats in the output of pacman -Fl on Arch Linux, which lists all files in all installable packages in the main repositories. The results are of course weighted towards established projects, rather than newer ones, toward images used for or by programs rather than graphics, towards programs like emacs with multiple variant packages, and toward formats for Linux. Counts may also be distorted by symlinks. A † indicates the entry is corrected for false positives (e.g., .pm is always Perl, not XPM, .ff can be force field data, .pfm is a often a font file instead of Portable Float Map, etc.)

Format Number of Paths Number of packages Example packages
All 7385118 14624
.ani 9 2 pop-icon-theme, python-scipy
.avif 3 1 vaultwarden-web
.bm, .xbm 704 29 swi-prolog, fricas, openbox
.bmp 1352 54 megaglest-data, lazarus, intel-oneapi-basekit
.cur 291 16 pop-icon-theme, reaper, lazarus
.dds 452 9 pioneer, sauerbraten-data, ogre-next
.emf, .emz 1 1 metasploit
.exr 33 3 blender, python-tests, pypy3
.ff, .ff.gz, .ff.bz2, .ff.zstd 0† 0†
.fits, .fts, .fit 64 4 python-astropy, root, root-cuda
.gif 26487 277 pysolfc-cardsets, scratch, openui5
.hdr, .rgbe, .xyze, .rad 84 7 python-astropy, materialx, enscript
.heif 0 0
.ibm, .lbm, .bbm, .ilbm 0 0
.icns 60 36 qmc2, racket, lazarus
.ico 715 236 reaper, lazarus, doxygen-docs
.j2k, .j2c, .jpc 2 1 emscripten
.jpg, .jpeg 28003 354 sauerbraten-data, freedroidrpg, povray
.jxl 30 1 gnome-backgrounds
.jxr, .hdp, .wdp 1 1 afl++
.kra 30 1 krita
.mng 35 30 launchy, gimp-help-ca, gimp-help-cs
.ora 0 0
.pam 0† 0†
.pbm 651 7 emacs, emacs-nativecomp, emacs-nox
.pcx, .pcc 2589† 4† rocksndiamonds-contrib, fpc-src
.pdf 14401 253 texlive-doc, rfc, ginkgo-hpc-docs
.pfm 0† 0†
.pgm 157 10 gimp, flowblade, kdenlive
.pic 8 3 texlive-doc, groff, plotutils
.pix 0† 0†
.png 564592 2313 nodejs-material-design-icons, obsidian-icon-theme
.pnm 3 3 imagemagick, python-pygame, texlive-doc
.ppm 41 16 lazarus, gimp, arrayfire
.ps, .eps 1683 65 texlive-doc, texlive-publishers, texlive-latexextra
.psd 51 9 mygui, deepin-system-monitor
.pxr 0 0
.qoi 0 0
.qtif, .qif 0† 0†
.raw 0† 0†
.rgb 90 8 opentoonz, opencascade, mesa-demos
.sct, .ct, .ch 0† 0†
.ras, .sun, .im1, .im8, .im24, .im32 3 3 python-tests, pypy, pypy3
.svg, .svgz 1056589 1556 papirus-icon-theme, tela-circle-icon-theme-black
.tga 345 16 megaglest-data, python-pybox2d, ogre
.tif, .tiff 132 17 opentoonz, dblatex, pd-gem
.webp 2950 29 naev, wesnoth, qt6-doc
.wmf 13 3 libreoffice-fresh-sdk, libreoffice-still-sdk, metasploit
.xcf 46 20 frogatto-data, gap-packages, mediawiki
.xpm 9933 113 xfwm4-themes, orchis-theme, icewm
.y4m 0 0

Looking over the packages in more detail, .xbm mostly lives in old GUI libraries and programs targeting X11; .xpm is mostly used by icon themes and by random applications that provide an XPM icon. XBM occurs a bit more often than PBM, while (thanks mainly to the icon theme effect that boosts PNG/SVG so much) XPM is a bit more common than the .pbm/.pgm/.ppm/.pnm family.

XBM and XPM can be created by ImageMagick, netpbm (via ppmtoxpm and pbmtoxbm), and libXpm; I am aware of loaders for both formats in imlib2, gdk-pixbuf, and Qt; xscreensaver has its own runtime XPM loader, and I wouldn't be surprised if some other old programs do the same. Because XBM/XPM are interpretable as C headers, they may be used to build some old programs.

XBM has a very simple specification at https://www.x.org/releases/X11R7.7/doc/libX11/libX11/libX11.html#Manipulating_Bitmaps. XPM's spec is at http://www.x.org/docs/XPM/xpm.pdf .

Implementation

Existing XPM decoders are mostly written in C and have historically had security issues. Even if they were safe and free of accidentally quadratic code, integrating them into Rust programs is inevitably painful.

It should not be difficult to make a simple, pure-Rust implementation, which does not panic or abort except on allocation failure. (XBM only needs an image buffer; XPM needs an image buffer and a resizable vector to store palette information.) Unsafe code and additional dependencies are not required. I'd guess at most 200 lines for XBM, and 500 for XPM would be needed. (If I have time, I'll try to write one and see if my guess is right. Edit: XBM took 500 lines, and XPM 900, although half of it is basic parsing+error handling helper code, and XPM has an 800-line color table which is put in an external crate to isolate its X11 license (= MIT + no advertising clause). See https://github.com/mstoeckl/image/commits/xbm/, https://github.com/mstoeckl/image/commits/xpm/, and https://github.com/mstoeckl/x11r6colornames)

The formats are uncompressed, and XBM can be decoded in O(n) time, where n is the file size; XPM in deterministic O(n log n) time.

XPM allows specifying colors by name, which would require embedding a copy of the 17kB X11 color name table. (Or it can be ignored: other than "black" and "white" I haven't seen any color names be used.)

XPM images technically support multiple contexts, where the palette may differ depending on whether one is rendering a color, grayscale (1,2 or 8 bit), or configurable-palette image; but in practice the color mode is the only one used, so I doubt anyone will ever ask for a different mode.

Since XBM/XPM are old, inefficient, and unlikely to be of interest for anything but image viewers, they may be worth putting in an 'obsolete-formats' library feature group that is disabled by default, so typical users can avoid compiling them and save 50kB or so of code+data.

Related: #2367 .

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant