I don't know how useful this is going to be for general purposes, because the data for a bitmap takes up 2.25K of ROM (9 pages, or 2304 bytes), so there's room for only a single bitmap in a 4K ROM, and the kernel isn't designed to take advantage of bankswitching (at least not yet), since the data needs to be in the same bank as the bitmap kernel. I may see if I can load the code for the active lines into zero-page RAM (if they'll fit and still leave enough room for other RAM usage), so that the kernel can display bitmaps stored in other banks-- but no promises about that.
I broke the kernel up into different sections, the intention being to allow room for squeezing a little bit of user code into the VSYNC routine, in addition to the usual overscan and vblank regions-- but I'll probably do away with the spare room in the VSYNC routine, since I'm going to set up the pointers in that section of code. (At present, the pointers are being set up outside the kernel, but that isn't very user-friendly!)
My original intention was to create a kernel for title screens, but first I decided to do a bitmap kernel. When I eventually do a title screen kernel, it will probably have multiple bitmap areas, like one for a large bitmap (maybe 96x128) for the title graphics, and a smaller area (maybe 48x64) for other text, such as a copyright message, or "press the fire button to begin," things like that. So this bitmap kernel isn't really intended for title screens per se, but it's sort of a step in that direction.
This WIP demo displays a drawing of a Celtic seahorse. (Don't ask me why he's biting one of his legs!) I'm including the original image for comparison. I resized it to fit inside a 96x192 area, and then decreased it from a 256-grayscale image to a 2-color image using dithering, which is why a lot of the lines look "dotted" or broken.