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:
- It doesn’t support all the options that this machine has, and
- It just uses a raster driver — and raster prints:
- Don’t come out looking quite as sharp (especially on the text), and
- 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:
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:
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] 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:
/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:
Now we can ask Homebrew to compile a new version for us with:
We can use otool
again to verify that GhostScript no longer needs a separate copy of libtiff
:
/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:
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:
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):
/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:
(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:
(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:
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:
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:
(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:
- Make sure you have the XCode Command Line tools installed by running
xcode-select --install
. - Install Homebrew.
- Install Foomatic-RIP (you can get it from here).
- Download the pxlcolor-Ricoh PPD.
- 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.) - Run
brew install libtiff
. - 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). - Run
brew install --build-from-source ghostscript
. (If you already have Ghostscript installed, runbrew reinstall --build-from-source ghostscript
instead.) - 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 runxcode-select --install
first.) cd /usr/libexec/cups/filter
sudo mkdir ghostscript
sudo cp -av /usr/local/Cellar/ghostscript/*/* ghostscript
sudo chown -R root:wheel ghostscript
sudo nano gswrapper
- 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=- - - Ctrl+O then Enter to save, then Ctrl+X to exit.
sudo chown root:wheel gswrapper
sudo chmod 755 gswrapper
cd /Library/Printers/PPDs/Contents/Resources
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)sudo nano Ricoh-Aficio_MP_C4502-pxlcolor-Ricoh.ppd
- Look for the
*FoomaticRIPCommandLine:
line. On the line directly below, changegs
togswrapper
. - Ctrl+O then Enter to save, then Ctrl+X to exit.
- Now open the System Preferences app and go to the Printers & Scanners section. Click on the “+” button to add a new printer.
- 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!