How I got a Ricoh Aficio MP C4502 Working on Mac OS X Mojave

Note: tl;dr at the end.

I recently came into possession of a Lanier MP C4502 (which is, as far as I can tell, just a re-branded Ricoh Aficio MP C4502). Thank god for government surplus. I have a Macbook that I use for work, and I wanted to see if I could get it to work with my Mac. My attempts were thusly:

  • Let Mac OS just detect and automatically install the driver. Well…turns out that the native Mac driver prints PostScript, and this thing didn’t come with a PostScript card — so the printer just tries to print the raw PostScript.
  • Install Gutenprint/Gimp-Print. It comes with a driver that works, technically…but:
    1. It doesn’t support all the options that this machine has, and
    2. It just uses a raster driver — and raster prints:
      1. Don’t come out looking quite as sharp (especially on the text), and
      2. Use up a lot of memory on the printer.

So I wanted to see if I could find a way to send PCL data to the printer instead.

I knew right off the bat that I’d probably need to use GhostScript, because GhostScript has a PCL driver built into it. I knew that OS X used CUPS as the underlying print system, so I started poking around trying to find where it kept its printer definition files (PPDs). It didn’t take me long to figure out that OS X copies them into /etc/cups/ppd at the time the printer is installed:

$ ls -l
total 7104
-rw-r--r-- 1 root _lp 21515 Aug 13 2018 HP_Officejet_Pro_8630.ppd
-rw-r--r-- 1 root _lp 41975 May 20 10:38 MPC_4502_w_Gutenprint.ppd

So now I could start tinkering around in with the PPDs.

I tried just adjusting the *cupsFilter line like so:

*cupsFilter: "application/vnd.cups-postscript 100 gs -sDEVICE=pxlcolor -dNOPAUSE -dBATCH -q -sOutputFile=- -"

Which didn’t work. At first, I thought it was because *cupsFilter wasn’t paying attention to the command line options I was providing; so I tried writing a simple bash script (called “pstopcl“) as a wrapper:

1
2
#!/bin/bash
gs -sDEVICE=pxlcolor -dNOPAUSE -dBATCH -q -sOutputFile=- -

And, for good measure, I did a sudo chown root:_lp pstopcl.

But this still didn’t work. When I went to go look at the CUPS’s error_log, I saw why:

D [20/May/2019:15:26:52 -0500] [Job 24] dyld: Library not loaded: /usr/local/opt/libtiff/lib/libtiff.5.dylib
D [20/May/2019:15:26:52 -0500] [Job 24] Referenced from: /usr/libexec/cups/filter/gs
D [20/May/2019:15:26:52 -0500] [Job 24] Reason: no suitable image found.  Did find:
D [20/May/2019:15:26:52 -0500] [Job 24] /usr/local/opt/libtiff/lib/libtiff.5.dylib: file system sandbox blocked stat()
D [20/May/2019:15:26:52 -0500] [Job 24] /usr/local/lib/libtiff.5.dylib: file system sandbox blocked stat()

So…I knew that there were some changes made to the printing subsystem in a previous version of Mac OS so that the printing subsystem was basically sandboxed from the rest of the system — it has to stay in its own little corner of the world and can’t access anything outside of that. So how do I fix this?

Well, step 1 was to recompile GhostScript. I originally installed GhostScript via Homebrew (using brew install ghostscript). If we know what libraries GhostScript depends on, we can turn them into static libraries; the linker will then bundle those libraries into the application at link time. Fortunately, otool will tell us what libraries the application is linked to:

$ otool -L /usr/local/bin/gs
/usr/local/bin/gs:
/usr/local/opt/libtiff/lib/libtiff.5.dylib (compatibility version 10.0.0, current version 10.0.0)
/usr/lib/libSystem.B.dylib (compatibility version 1.0.0, current version 1252.200.5)
/usr/lib/libiconv.2.dylib (compatibility version 7.0.0, current version 7.0.0)

Oh good — libtiff is really the only one we need to worry about. If we look at /usr/local/opt/libtiff/lib, we can see that there’s both a dynamic library and a static library there. If we just rename the dynamic library, it’ll get ignored at link time and the static version will get compiled in instead. All we need to do is:

$ mv /usr/local/opt/libtiff/lib/libtiff.5.dylib /usr/local/opt/libtiff/lib/libtiff.5.dylib.hidden

Now we can ask Homebrew to compile a new version for us with:

$ brew reinstall ghostscript --build-from-source

We can use otool again to verify that GhostScript no longer needs a separate copy of libtiff:

$ otool -L /usr/local/bin/gs
/usr/local/bin/gs:
/usr/lib/libSystem.B.dylib (compatibility version 1.0.0, current version 1252.250.1)
/usr/lib/libiconv.2.dylib (compatibility version 7.0.0, current version 7.0.0)

Great! Now we just need to be sure to “unhide” the version of libtiff that we just hid:

$ mv /usr/local/opt/libtiff/lib/libtiff.5.dylib /usr/local/opt/libtiff/lib/libtiff.5.dylib.hidden

Now, I took GhostScript’s entire directory and copied it into CUPS’s filter subdirectory (which I probably didn’t need to do, strictly speaking; but I did it anyway):

1
2
3
$ cd /usr/libexec/cups/filter
$ sudo mkdir ghostscript
$ sudo cp -av /usr/local/Cellar/ghostscript/9.26_1/* ghostscript

We also need to be sure to change ownership of everything in that folder:

$ sudo chown -R root:wheel ghostscript

Now I just needed to update my pstopcl wrapper script to point to the new copy of gs:

1
2
#!/bin/bash
/usr/libexec/cups/filter/ghostscript/bin/gs -sDEVICE=pxlcolor -dNOPAUSE -dBATCH -q -sOutputFile=- -

The next issue was that Ghostscript was complaining that it couldn’t find gs_init.ps — so we had to help it out. Ghostscript has a set of directories where it will search for this file compiled in, which we can list with gs --help (output truncated):

Search path:
/usr/local/Cellar/ghostscript/9.26_1/share/ghostscript/9.26/Resource/Init :
/usr/local/Cellar/ghostscript/9.26_1/share/ghostscript/9.26/lib :
/usr/local/Cellar/ghostscript/9.26_1/share/ghostscript/9.26/Resource/Font :
/usr/local/Cellar/ghostscript/9.26_1/share/ghostscript/fonts :
/usr/local/Cellar/ghostscript/9.26_1/share/fonts/default/ghostscript :
/usr/local/Cellar/ghostscript/9.26_1/share/fonts/default/Type1 :
/usr/local/Cellar/ghostscript/9.26_1/share/fonts/default/TrueType :
/usr/lib/DPS/outline/base : /usr/openwin/lib/X11/fonts/Type1 :
/usr/openwin/lib/X11/fonts/TrueType

Ok — so Ghostscript is trying to look in a bunch of Homebrew directories — and since those are owned by my user account, OS X’s sandboxing is probably blocking Ghostscript from being able to access them at print time. Since we copied those directories into CUPS’s filter directory, we just need to adjust the paths; we can then tell Ghostscript to look in those directories. We’ll add in OS X’s fonts folder for good measure:

1
2
#!/bin/bash
/usr/libexec/cups/filter/ghostscript/bin/gs -I/Library/Fonts:/usr/libexec/cups/filter/ghostscript/share/ghostscript/9.26/Resource/Init:/usr/libexec/cups/filter/ghostscript/share/ghostscript/9.26/lib:/usr/libexec/cups/filter/ghostscript/share/ghostscript/9.26/Resource/Font:/usr/libexec/cups/filter/ghostscript/share/ghostscript/fonts:/usr/libexec/cups/filter/ghostscript/share/fonts/default/ghostscript:/usr/libexec/cups/filter/ghostscript/share/fonts/default/Type1:/usr/libexec/cups/filter/ghostscript/share/fonts/default/TrueType:/usr/lib/DPS/outline/base:/usr/openwin/lib/X11/fonts/Type1:/usr/openwin/lib/X11/fonts/TrueType -sDEVICE=pxlcolor -dNOPAUSE -dBATCH -q -sOutputFile=- -

So…this got me partway there. I was able to do a test print that didn’t look like complete garbage…but it did look like garbage (and note, it only took up 1/4 of the page):

So I knew I was getting close — now I know that Ghostscript will run.

I started doing some more searching around. I looked on openprinting.org; it turns out that they already have multiple PPDs for the MP C4502, including one that outputs in PCL. Great! Let’s see if we can get that to work.

Looking at the PPD, I could tell that there were a lot of Foomatic-RIP options in this PPD. I knew the latest version of Foomatic for OS X was a little older and only advertised that it worked up through Mavericks (10.9), and I started contemplating whether I could write a script to stand in for Foomatic; but ultimately I decided to just give Foomatic a try. Turns out, it worked almost out of the box — I didn’t need to do anything.

The PPD has the Ghostscript command line built into it:

*FoomaticRIPCommandLine: "(printf '\033%%-12345X@PJL\n@PJL JOB\n@PJL SET COPIES=&copies;\n'%G|perl -p -e "s/\x26copies\x3b/1/");
(gs -q -dBATCH -dPARANOIDSAFER -dNOPAUSE -dNOINTERPOLATE %B%A%C %D%E | perl -p -e "s/^\x1b\x25-12345X//" | perl -p -e "s/\xc1\x01\x00\xf8\x31\x44/\x44/g");
(printf '@PJL\n@PJL EOJ\n\033%%-12345X')"
*End

So I thought, “ok, maybe I can just get rid of my wrapper script and just plug the contents of the -I switch straight into the PPD”, like so:

*FoomaticRIPCommandLine: "(printf '\033%%-12345X@PJL\n@PJL JOB\n@PJL SET COPIES=&copies;\n'%G|perl -p -e "s/\x26copies\x3b/1/");
(gs -I/Library/Fonts:/usr/libexec/cups/filter/ghostscript/share/ghostscript/9.26/Resource/Init:/usr/libexec/cups/filter/ghostscript/share/ghostscript/9.26/lib:/usr/libexec/cups/filter/ghostscript/share/ghostscript/9.26/Resource/Font:/usr/libexec/cups/filter/ghostscript/share/ghostscript/fonts:/usr/libexec/cups/filter/ghostscript/share/fonts/default/ghostscript:/usr/libexec/cups/filter/ghostscript/share/fonts/default/Type1:/usr/libexec/cups/filter/ghostscript/share/fonts/default/TrueType:/usr/lib/DPS/outline/base:/usr/openwin/lib/X11/fonts/Type1:/usr/openwin/lib/X11/fonts/TrueType -q -dBATCH -dPARANOIDSAFER -dNOPAUSE -dNOINTERPOLATE %B%A%C %D%E | perl -p -e "s/^\x1b\x25-12345X//" | perl -p -e "s/\xc1\x01\x00\xf8\x31\x44/\x44/g");
(printf '@PJL\n@PJL EOJ\n\033%%-12345X')"
*End

Great — I’ve got a PPD ready. Time to install it. I copied the PPD over to OS X’s printers database, like so:

$ sudo -s
Password:
# cd /Library/Printers/PPDs/Contents/Resources
# cat ~/Downloads/Ricoh-Aficio_MP_C4502-pxlcolor-Ricoh.ppd | gzip >RICOH\ Aficio\ MP\ C4502\ PCL.gz
# exit

Now I was able to go into my System Preferences and add the printer. In the PPD, the short name is set to “Ricoh Aficio MP C4502 PXL” — the “PXL” suffix helped me distinguish it from the drivers that are available on the Apple Store.

But…when I tried to print off a test page, it failed with the following:

E [22/May/2019:14:22:06 -0500] Line longer than the maximum allowed (255 characters) on line 53 of /private/etc/cups/ppd/Lanier_MP_C4502___On_VPN.ppd.

Well crap — that list of include directories makes the command line too long. Turns out I needed my wrapper script after all. So, I restored the FoomaticRIPCommandLine back to what it was, then modified my wrapper script to eliminate the duplicate options that were already being supplied by the FoomaticRIPCommandLine:

1
2
#!/bin/bash
/usr/libexec/cups/filter/ghostscript/bin/gs -I/Library/Fonts:/usr/libexec/cups/filter/ghostscript/share/ghostscript/9.26/Resource/Init:/usr/libexec/cups/filter/ghostscript/share/ghostscript/9.26/lib:/usr/libexec/cups/filter/ghostscript/share/ghostscript/9.26/Resource/Font:/usr/libexec/cups/filter/ghostscript/share/ghostscript/fonts:/usr/libexec/cups/filter/ghostscript/share/fonts/default/ghostscript:/usr/libexec/cups/filter/ghostscript/share/fonts/default/Type1:/usr/libexec/cups/filter/ghostscript/share/fonts/default/TrueType:/usr/lib/DPS/outline/base:/usr/openwin/lib/X11/fonts/Type1:/usr/openwin/lib/X11/fonts/TrueType $@ -sOutputFile=- -

And changed the FoomaticRIPCommandLine to point to the wrapper script:

*FoomaticRIPCommandLine: "(printf '\033%%-12345X@PJL\n@PJL JOB\n@PJL SET COPIES=&copies;\n'%G|perl -p -e "s/\x26copies\x3b/1/");
(pstopxl -q -dBATCH -dPARANOIDSAFER -dNOPAUSE -dNOINTERPOLATE %B%A%C %D%E | perl -p -e "s/^\x1b\x25-12345X//" | perl -p -e "s/\xc1\x01\x00\xf8\x31\x44/\x44/g");
(printf '@PJL\n@PJL EOJ\n\033%%-12345X')"
*End

And finally…success! I was able to get a nice test page with crisp text on it:

tl;dr: Here’s the procedure for getting this up and running:

  1. Make sure you have the XCode Command Line tools installed by running xcode-select --install.
  2. Install Homebrew.
  3. Install Foomatic-RIP (you can get it from here).
  4. Download the pxlcolor-Ricoh PPD.
  5. Open the PPD with your favorite text editor. Change *cupsFilter: "application/vnd.cups-pdf 0 foomatic-rip" to *%cupsFilter: "application/vnd.cups-pdf 0 foomatic-rip". (e.g., you’re adding a % near the beginning of the line.)
  6. Run brew install libtiff.
  7. Run mv /usr/local/opt/libtiff/lib/libtiff.5.dylib /usr/local/opt/libtiff/lib/libtiff.5.dylib.hidden (to hide the libtiff dynamic library).
  8. Run brew install --build-from-source ghostscript. (If you already have Ghostscript installed, run brew reinstall --build-from-source ghostscript instead.)
  9. Run otool -L /usr/local/bin/gs. Make sure that libtiff is not shown in the output. (If you get a “command not found” error, you might need to run xcode-select --install first.)
  10. cd /usr/libexec/cups/filter
  11. sudo mkdir ghostscript
  12. sudo cp -av /usr/local/Cellar/ghostscript/*/* ghostscript
  13. sudo chown -R root:wheel ghostscript
  14. sudo nano gswrapper
  15. Paste the following into the new file:
    1
    2
    #!/bin/bash
    /usr/libexec/cups/filter/ghostscript/bin/gs -I/Library/Fonts:/usr/libexec/cups/filter/ghostscript/share/ghostscript/9.26/Resource/Init:/usr/libexec/cups/filter/ghostscript/share/ghostscript/9.26/lib:/usr/libexec/cups/filter/ghostscript/share/ghostscript/9.26/Resource/Font:/usr/libexec/cups/filter/ghostscript/share/ghostscript/fonts:/usr/libexec/cups/filter/ghostscript/share/fonts/default/ghostscript:/usr/libexec/cups/filter/ghostscript/share/fonts/default/Type1:/usr/libexec/cups/filter/ghostscript/share/fonts/default/TrueType:/usr/lib/DPS/outline/base:/usr/openwin/lib/X11/fonts/Type1:/usr/openwin/lib/X11/fonts/TrueType $@ -sOutputFile=- -
  16. Ctrl+O then Enter to save, then Ctrl+X to exit.
  17. sudo chown root:wheel gswrapper
  18. sudo chmod 755 gswrapper
  19. cd /Library/Printers/PPDs/Contents/Resources
  20. sudo cp ~/Downloads/Ricoh-Aficio_MP_C4502-pxlcolor-Ricoh.ppd . (change ~/Downloads/Ricoh-Aficio_MP_C4502-pxlcolor-Ricoh.ppd to wherever you downloaded your PPD to)
  21. sudo nano Ricoh-Aficio_MP_C4502-pxlcolor-Ricoh.ppd
  22. Look for the *FoomaticRIPCommandLine: line. On the line directly below, change gs to gswrapper.
  23. Ctrl+O then Enter to save, then Ctrl+X to exit.
  24. Now open the System Preferences app and go to the Printers & Scanners section. Click on the “+” button to add a new printer.
  25. Find the printer. In my case, I have the printer hooked up to my network, so I clicked on the “IP” tab, then entered the IP address for my printer. (You can use either “Internet Printing Protocol – IPP” or “Line Printer Daemon – LPD”; however, I’ve found that the Line Printer Daemon option works a little better, because OS X doesn’t whine about errors when adding the printer.) In the “Use” drop-down, choose “Select Software”, then find the one named “Ricoh Aficio MP C4502 PXL”. When you’re done, click “Add”.

And you’re done! Print off a test page and enjoy your new printer!