mailto: blog -at- heyrick -dot- eu

Printing to a Samsung SL-M2022W IPP laser printer from RISC OS

The state of printing on RISC OS today

RISC OS is provided with a rich set of printer drivers, with support for many manufacturers - Brother, Canon, Epson, HP, Mannesmann Tally, Olivetti, Qume, Star...

Maybe some of those names might have given away that it was reasonably good support for the early '90s.

Printing support on RISC OS nowadays is pretty poor. The general "solution" (in scare quotes) is to print to a PDF and then use something else to send the data to a printer. But even that's a broken solution - the standard PostScript driver outputs complete gibberish when faced with Unicode. There is a solution but it costs £35/€40 which is a bit steep when you consider that it only creates proper PostScript, it doesn't send anything to a printer, and my entire inkjet cost less. So, one can finally print Japanese with it, but we're still stuck with the problem of getting data to a printer.


Playing with IPP

Something that I have been working on for a while is in detecting and interacting with IPP (Internet Printing Protocol) printers. It's not difficult to scan for and open a port to retrieve information about a printer, once you understand that IPP is basically like an HTTP request, only it uses a binary payload. That is to say, things are tagged with bytes of specific value rather than keywords.

The problem with IPP is that it primarily comes in two flavours. The most recent version, that might be useful to RISC OS, is thanks to the IPP Everywhere initiative, making an open specification on ways to communicate with networked printers. In the long run, supporting this on RISC OS will give the platform the ability to access a new generation of modern printing devices.
The older incarnation of IPP specified the transport. It did not specify the raster format, and for this, the de facto standard is Apple's "AirPrint". The raster format in use here is called "URF", which probably means something like Unified Raster Format. There appear to be at least a dozen or so incarnations, and only one (a 24 bit RGB packbits style encoding) has been known to have been decoded. Sort of. There's a lot of parts marked as unknown. Sending that data to my HP 3630 inkjet did work, but sending it to my laser failed. Not a surprise really, what's a monochrome laser to do with 24 bit RGB?
All of the other support via drivers for PCs, or custom drivers on Android, use device specific protocols. For my inkjet, that's PCL3GUI as far as I can tell, and for the laser it's QPDL.
Neither of those are officially documented either.


The printer

The sacrificial lamb printer in question is a Samsung SL-M2022W.
It is a low cost simple monochrome laser printer, that is discussed here.


My next great idea

Yesterday, began the day with the idea of printing to a generic laserjet and translating that into a monochrome sprite:

The plan was to then slice this into something that could be converted to QPDL for use with my laser.
This step was going to be slow, but would be necessary because older printers accept their raster data row by row, while it appears the QPDL breaks the bitmap into slices, and then encodes vertically within each slice, as is better explained by a simple drawing (actual slices are 128 pixels, this is simplified for clarity):

That's where I hit a roadblock. QPDL is compressed. Not in the sort-of-packbits like everything else, but in a method that uses bits of uncompressed data and a table of entries into it for reconstituting the rest of the data. I'm not very good at mathematics, so the description of what was going on was... well... gibberish. I also was not intending to so much as look at the source code of the existing (splix) implementation for Linux, because it was licenced GPL and I wanted this to be entirely my own work (so could be anything other than GPL).
I had an example dump from Windows (print to file) and that's when I noticed something:

It wasn't just a raw dump of the QPDL data, it was prefixed with a lot of PJL. That's HP's "Printer Job Language" that sets up a number of attributes before specifying which "language" to switch to for the data, in this case, QPDL.


Fun with PCL

So, I thought, why not - just as a test - try some PCL (HP's Printer Command Language, what people used to mean when they said "LaserJet compatible" though it's evolved a lot since then).

So I replaced the file with this:

<esc>%-12345X@PJL JOB NAME "A Test"<cr><lf>
The things in angle brackets are explaining characters not directly visible, namely ASCII 27 for escape, and the usual carriage return/life feed pairing.

Nothing happened. This was good, the printer wasn't throwing an error.

Time to flesh it out a little.

<esc>%-12345X@PJL JOB NAME "A Test"<cr><lf>
<esc>%-12345X@PJL EOF<cr><lf>

And this was accepted, resulting in a page that said "Hello!" (and not "EHello!").

One more test:

<esc>%-12345X@PJL JOB NAME "A Test"<cr><lf>
<esc>%-12345X@PJL EOF<cr><lf>

This had the same effect, only the "Hello!" was printed further away from the edges of the page.

Which meant this printer, that made no mention of supporting PCL in it's IPP data block, and which specifically claimed not to support PCL in the instruction booklet...
...actually appears to support PCL.

So I decided to just go for it. I took the entire raster bitmap that I'd already generated and pasted it in place of the "Hello!" line. All megabyte or so of it.


Okay, it didn't entirely work, I got about an inch of print followed by gibberish, but this was a mere implementation issue (the printer probably cacked itself it have a megabyte tossed to it in a manner of seconds). The important thing was that the SL-M2022W was actually capable of understanding output intended for an HP LaserJet.

This was the first time I've had a native printout from RISC OS in around 15 years, and given the last time was something that had a parallel port attached to a RiscPC, this is the first time I've had native 32 bit RISC OS printing anything by itself ever.

It's probably sad that that's a big moment, but there you go... I'm sad and proud of it.



The rest of the day was spent making a program to scan the network looking for a compatible printer, and then trickle-feeding (the printer is actually kind of slow at dealing with this) data to it. And then making my program (that was originally "a hack") into something a little more bombproof. At least good enough that it can work.

Printing is actually a two-stage process. Something (whatever) is printed from RISC OS to a file. When that has completed, you run my program that takes the file, adds some PCL preamble, and then feeds it to the printer. Maybe one day this could be added directly to !Printers, to print to a raw port (9100) on a specific IP address? But for now it's a two-stage process. But I'm perfectly happy with that, as my program can work in a TaskWindow (so doesn't tie up the machine) and it's a lot less crap than making everything into a PDF and then fetching that from Windows or my phone to then do the actual printing.


Will it work for you?

If you have an IPP (WiFi/mobile printing) laser printer, then I'd suggest giving it a try. It may not work, I don't know how widespread support for HP's PCL is. I was actually pretty surprised that it worked at all with my printer. There are some nice printers that can print directly from an uploaded PDF. My SL-M2022W, on the other hand, is a budget laser that is pretty inexpensive but punches above its weight with some useful features like the NFC tap-to-print (so friends can print directly to it without having to associate with your WiFi). It also supported PCL too. So maybe your printer might as well?

If you have a colour inkjet, not only is this unlikely to work (being a mono raster), my program will specifically discount your printer as compatible. This is primarily because my inkjet is a lower IP address and I wanted to find the laser printer not the inkjet.


Setting up your system

Load !Printers, and click on any of the icons on the iconbar.

Click on Install new printer. A window with numerous directories will open. Double-click on the HP directory to open it, and then double-click on the LasJet-6 file.

A new icon will appear on the iconbar.

Menu-click on the new icon to open the menu, and choose the third option down, Printer control....

The printer control window will open:

Menu-click on the new printer name to open the control menu, and choose Configure....

In the configuration window, change the name to something to reflect your printer.
Then set the quality to High (600dpi) - that counts as "normal" these days. RISC OS doesn't have 1,200dpi capabilities.
The rest (paper feed auto, quality grey/diffused) can be left at their default settings.

Close that window, call up the menu again, and choose Connection....

Here, you can tick Print in background if you like.
In the list of connection choices, select File and set the destination to be <Wimp$ScrapDir>.LJ6data.

Smile as you click on Set that the other setup window had an 'OK' button, not a 'Set' button. Such consistency from the people that wrote The Style Guide. ☺

Go back to the iconbar icon, and click on Save choices, or all of this will be forgotten when you next start !Printers.


Your first print

With !Printers loaded, click on the printer to make it the current one (cream, not grey):

Load up whatever document you would like to print. Here you can see the lyrics to the song Hello, shooting star by moumoon in Ovation.

The group is called "moumoon", and since we're printing a raster bitmap directly from RISC OS, you can print anything that FontManager is capable of dealing with.
Note: If you don't have Ovation and you'd like a superior word processor / basic desktop publisher, you can pick up a copy from right here.

Choose to Print. This is Ovation's print dialogue. Yours will be sort-of-similar. Let it get on with things.

The job isn't done yet. You have a printer file, but what to do with it?

That's where SammyPrint comes into play.

Unpack SammyPrint and double-click to run it. Your computer will pause while SammyPrint does its stuff. That is to say, it will scan your local network for compatible IPP printers. The first compatible printer that it finds (active, mono, supports URF) will have the printout sent to it.
[hourglass]You can see what SammyPrint is doing by looking at the hourglass that appears. If the upper LED is being shown (as in the hourglass shown on the left here) that means that your network is being scanned to look for compatible printers. Scanning is in numerical order, so it'll find x.x.x.8 much faster than x.x.x.99.
While attempting to connect to a printer, the lower LED will be shown, And when actually sending data, the percentage counter will count up reflecting how much has been sent.

If it worked, then that's it.
Printing is a two-stage process. Print to file as if for a LaserJet 6, then use SammyPrint to find an IPP printer and send the data to it.


And if it didn't print?

Normally there are no messages at all from SammyPrint, it will only muck around with the hourglass to reflect its status.
However, if you should get a message...

  • Expected to find "<Wimp$ScrapDir>.LJ6data" containing PCL data.
    This means that the print data file could not be found. You must print to this file before using SammyPrint.
  • Unable to determine this machine's IP address.
    The system variable Inet$EtherIPAddr has not been set. Is your machine correctly connected to a local network? [double check this if using DHCP]
  • Unable to locate a potentially compatible printer.
    This means that a scan of all the possible LAN addresses (like 192.168.1.x where x is 1 to 255) did not find any printer responding to IPP requests on port 631 that are active, monochrome, and support URF.
    To explain - active is obvious. The monochrome (or rather, not colour) test is to discount colour inkjets and the like, and the test for supporting URF means it's an AirPrint printer as opposed to a dumb raw print server that is sometimes built into ADSL routers. These tests should hopefully narrow down to a monochrome laser printer.
    If you still don't have any joy, then download my "FindIPP" program (search the ROOL forums for a link) which will perform a similar scan and tell you what it found.
  • Unable to connect to port 9100 on x.x.x.x - does this printer support raw?
    First up, check the IP address shown is correct, that you're actually connecting to the right device.
    Then check the device configuration. It is possible to disable raw (port 9100) support. Obviously if you do then you can't print that way...
  • File "<Wimp$ScrapDir>.LJ6data" could not be opened...
    This shouldn't happen - does something still have it open for writing or update?

And, on the printer side:

  • Nothing happens.
    Your printer probably doesn't support printing PCL in this manner.
  • Some sort of error message, code, or blinking red indicator.
    Your printer probably doesn't support printing PCL in this manner.
  • Your printer starts printing gibberish, the top of which says "%-12345X"
    Your printer probably doesn't support printing PCL in this manner.
  • Your printer bursts into flames.
    Your printer really didn't appreciate being fed generic PCL. It can only exist when fed proprietary manufacturer-sanctioned rubbish. Anything else gives it heartburn, diarrhoea, and trophozoite acanthamoebae (and that's the best case scenario).

Generally speaking, if it doesn't work it probably won't work.


What to do next?

If it does not work, delete the LJ6 printer profile that you added to !Printers. I'm sorry if it doesn't work for you, but on the plus side you're no worse off than you were before.

If it does work, then I suggest you rename SammyPrint to !SammyPrint and place it in $.Apps so it'll get added to your Apps resource for easy access.
Alternatively, create a TaskObey file to run SammyPrint, and drop that in Apps. The program is just as happy running in a TaskWindow - it'll still report its activity using the hourglass, but your machine will carry on multitasking.

Either way please drop a note on the ROOL forum to let me know how you get on.


Updated 2019/07/30

SammyPrint has been updated (to version 0.02 - please update if you downloaded an earlier version).

This version includes a number of command line options to tailor its behaviour:

SammyPrint -?
Syntax: SammyPrint [-colour] [-file <filename>] [-ip <addr>] [-nopreamble] [-verbose] 
        -colour     to allow colour printers to be accepted in network scan
        -file <f>   to use a file other than <Wimp$ScrapDir>.LJ6data.
        -ip <addr>  is an IP address of a printer, device will NOT
                    be checked for compatibility first.
        -nopreamble to send data verbatim, without PJL setup.
        -verbose    to be talkative (best used in a TaskWindow)

  To print a LaserJet 6 output to a Samsung M2022W laser printer:
  To do likewise, but specify the printer:
    SammyPrint -ip
  To send "$.kittens.jpeg" to an HP3630 inkjet:
    SammyPrint -colour -file "$.kittens/jpeg" -nopreamble -verbose
    (this may work also for PDFs or PostScript if supported by the printer)

This is SammyPrint version 0.02 (30th July 2019) by Rick Murray.
Please refer to

If you specify no options, it will behave as before - scanning for a monochrome AirPrint printer to send it the printout file <Wimp$ScrapDir>.LJ6data (as described above).

However, you can now...

  • -colour
    To include colour printers in the IPP printer scanning. The LaserJet 6 output is a monochrome bitmap aimed at laser printers so originally SammyPrint ignored colour printers. However new functionality means you may want to handle colour printers.
  • -file <filename>
    To send a different file to your printer. Where this comes into its own is when you realise that some printers accept a different range of files such as JPEG, PostScript, or PDF (depends upon printer).
  • -ip <ip address>
    To specify the IP address of the printer directly. When you do this, no IPP validation will be performed as it's assumed that you have already chosen it as the printer device to use.
  • -nopreamble
    To not send the PJL setup stuff (or validate the input data is PCL). You'll want this if sending some other sort of data to your printer.
  • -verbose
    To make SammyPrint give a running commentary of what it is doing. This can be useful when diagnosing problems.

Working examples:

  • Send the PCL file "$.pcldump" to the Samsung M2022W (looking for it)
    SammyPrint -file "$.pcldump"

  • Send a QPDL file (generated on Windows) to the Samsung M2022W printer at
    SammyPrint -file "$.qpdlfile" -ip

  • Send a JPEG to an HP 3630 inkjet (it'll be printed to fill the page)
    SammyPrint -file "$.kittens/jpeg" -colour -nopreamble -verbose

  • Kittens to the HP 3630, but specify IP address
    SammyPrint -file "$.kittens/jpeg" -ip -verbose

  • And finally, the same but done 'quickly'
    SammyPrint -f "$.kittens/jpeg" -i -v

That last example works because SammyPrint actually only looks at the first character of the parameter, so -nopreamble, -n, -nobrexit and -nowayjose all look the same...

As before, please let me know how you get on.



Your comments:

Please note that while I check this page every so often, I am not able to control what users write; therefore I disclaim all liability for unpleasant and/or infringing and/or defamatory material. Undesired content will be removed as soon as it is noticed. By leaving a comment, you agree not to post material that is illegal or in bad taste, and you should be aware that the time and your IP address are both recorded, should it be necessary to find out who you are. Oh, and don't bother trying to inline HTML. I'm not that stupid! ☺ ADDING COMMENTS DOES NOT WORK IF READING TRANSLATED VERSIONS.
You can now follow comment additions with the comment RSS feed. This is distinct from the b.log RSS feed, so you can subscribe to one or both as you wish.

David Pilling, 30th July 2019, 19:56
"the standard PostScript driver outputs complete gibberish when faced with Unicode" as it does when faced with anything else (sprites with masks).
David Pilling, 31st July 2019, 13:41
cf RComp Uniprint
Rick, 31st July 2019, 13:50
UniPrint - a good solution (with price comparable to the PS3 driver), let down only slightly by the fact that it needs another computer to do the actual grunt work. ;-) 
Yesterda y evening I printed Frobnicate issue 31 (the Frenchie one) completely from RISC OS on my Pi. Just told OvationPro to print it as a pamphlet doing the even pages, then the odds as two separate jobs. Then did it all again because I put the turned pages in the wrong way up (duh!). Took about five minutes, required nothing else. I'm happy with that.
David Pilling, 1st August 2019, 13:31
Good point about IPP having a bitmap format - that's the key - which I'd not taken in.
David Pilling, 1st August 2019, 16:03
In a way then printers have come full circle, what did the damage to RISC OS and inspired things like Uniprint was complicated secret command sets. Things which needed a lot of code and inside knowledge to get good results. 
David Pilling, 1st August 2019, 16:04
PS Good work!
Timo Hartong, 2nd October 2023, 23:27
I can now print on my network printer from the Pinebook Pro this is fantastic

Add a comment (v0.11) [help?] . . . try the comment feed!
Your name
Your email (optional)
Validation Are you real? Please type 04661 backwards.
Your comment
French flagSpanish flagJapanese flag
«   July 2019   »

(Felicity? Marte? Find out!)

Last 5 entries

List all b.log entries

Return to the site index



Search Rick's b.log!

PS: Don't try to be clever.
It's a simple substring match.


Last read at 15:02 on 2024/05/26.

QR code

Valid HTML 4.01 Transitional
Valid CSS
Valid RSS 2.0


© 2019 Rick Murray
This web page is licenced for your personal, private, non-commercial use only. No automated processing by advertising systems is permitted.
RIPA notice: No consent is given for interception of page transmission.


Have you noticed the watermarks on pictures?
Next entry - 2019/08/14
Return to top of page