#!/bin/sh #* Copyright (C) 2003-2006 Rick Richardson #* #* This program is free software; you can redistribute it and/or modify #* it under the terms of the GNU General Public License as published by #* the Free Software Foundation; either version 2 of the License, or #* (at your option) any later version. #* #* This program is distributed in the hope that it will be useful, #* but WITHOUT ANY WARRANTY; without even the implied warranty of #* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the #* GNU General Public License for more details. #* #* You should have received a copy of the GNU General Public License #* along with this program; if not, write to the Free Software #* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. #* #* Authors: Rick Richardson VERSION='$Id: foo2oak-wrapper.in,v 1.28 2007/06/11 00:48:32 rick Exp $' PROGNAME="$0" BASENAME=`basename $PROGNAME` PREFIX=/usr SHARE=$PREFIX/share/foo2oak PATH=$PATH:/sw/bin:/opt/local/bin # # Log the command line, for debugging and problem reports # if [ -x /usr/bin/logger ]; then logger -t "$BASENAME" -p lpr.info -- "foo2oak-wrapper $@" x Set device resolution in pixels/inch [$RES] -s source Source code to send to printer [$SOURCE] 1=tray1, 4=manual, 7=auto Code numbers may vary with printer model. -2/-3/-4/-6/-8/-10/-12/-14/-15/-16/-18 Print with N-up (requires psutils) -o orient For N-up: -op is portrait, -ol is landscape, -os is seascape. Printer Tweaking Options: -u x Set offset of upper left printable in pixels [varies] -l x Set offset of lower right printable in pixels [varies] -L mask Send logical clipping values from -u/-l in ZjStream [3] 0=no, 1=Y, 2=X, 3=XY Color Tweaking Options: -g gsopts Additional options to pass to Ghostscript, such as -dDITHERPPI=nnn, etc. May appear more than once. [] -G profile.icm Convert profile.icm to a Postscript CRD using icc2ps and adjust colors using the setcolorrendering PS operator. $SHARE/icm/ will be searched for profile.icm. -I intent Select profile intent from ICM file [$INTENT] 0=Perceptual, 1=Colorimetric, 2=Saturation, 3=Absolute -G gamma-file.ps Prepend gamma-file to the Postscript input to perform color correction using the setcolortransfer PS operator. Debugging Options: -S plane Output just a single color plane from a color print [all] 1=Cyan, 2=Magenta, 3=Yellow, 4=Black -D lvl Set Debug level [$DEBUG] -V $VERSION EOF exit 1 } # # Report an error and exit # error() { echo "$BASENAME: $1" >&2 exit 1 } dbgcmd() { if [ $DEBUG -ge 1 ]; then echo "$@" >&2 fi "$@" } # # N-up-ify the job. Requires psnup from psutils package # nup() { case "$NUP" in [2368]|1[0458]) tr '\r' '\n' | psnup $NUP_ORIENT -d2 -$NUP -m.3in -p$paper -q ;; [49]|1[26]) tr '\r' '\n' | psnup $NUP_ORIENT -d2 -$NUP -m.5in -p$paper -q ;; *) error "Illegal call to nup()." ;; esac } # # Process the options # BPP=1 GSBIN=gs CMDLINE="$*" DEBUG=0 DUPLEX=1 COLOR= QUALITY=1 MEDIA=1 COPIES=1 PAPER=1 RES=600x600 SOURCE=7 NUP= CLIP_UL= CLIP_LR= CLIP_LOG= BC= AIB= COLOR2MONO= GAMMAFILE= INTENT=0 GSOPTS= GSDEV=-sDEVICE=pbmraw NUP_ORIENT= while getopts "1:23456789o:b:cd:g:l:u:L:m:n:p:q:r:s:ABS:D:G:I:Vh?" opt do case $opt in b) BPP=$OPTARG;; c) COLOR=-c;; d) DUPLEX="$OPTARG";; g) GSOPTS="$GSOPTS $OPTARG";; m) MEDIA="$OPTARG";; n) COPIES="$OPTARG";; p) PAPER="$OPTARG";; q) QUALITY="$OPTARG";; r) RES="$OPTARG";; s) SOURCE="$OPTARG";; l) CLIP_LR="-l $OPTARG";; u) CLIP_UL="-u $OPTARG";; L) CLIP_LOG="-L $OPTARG";; A) AIB=-A;; B) BC=-B;; S) COLOR2MONO="-S$OPTARG";; D) DEBUG="$OPTARG";; G) GAMMAFILE="$OPTARG";; I) INTENT="$OPTARG";; [234689]) NUP="$opt";; [57]) error "Can't find acceptable layout for $opt-up";; 1) case "$OPTARG" in [024568]) NUP="1$OPTARG";; *) error "Can't find acceptable layout for 1$OPTARG-up";; esac ;; o) case "$OPTARG" in l*) NUP_ORIENT=-l;; s*) NUP_ORIENT=-r;; p*|*) NUP_ORIENT=;; esac;; V) echo "$VERSION"; foo2oak -V; exit 0;; h|\?) if [ "$CMDLINE" != "-?" -a "$CMDLINE" != -h ]; then echo "Illegal command:" echo " $0 $CMDLINE" echo fi usage;; esac done shift `expr $OPTIND - 1` # # If there is an argument left, take it as the file to print. # Else, the input comes from stdin. # if [ $# -ge 1 ]; then if [ "$LPJOB" = "" ]; then LPJOB="$1" fi exec < $1 fi # # Select the ghostscript device to use # case "$BPP" in 1) if [ "" = "$COLOR" ]; then GSDEV=-sDEVICE=pbmraw else GSDEV=-sDEVICE=bitcmyk fi ;; 2) if [ "" = "$COLOR" ]; then GSDEV=-sDEVICE=pgmraw else GSDEV="-sDEVICE=cups -dcupsColorSpace=6 -dcupsBitsPerColor=2" fi ;; *) error "Illegal number of bits per plane ($BPP)";; esac # case "$QUALITY" in 0) GSOPTS="-dCOLORSCREEN $GSOPTS" ;; 1) GSOPTS="-dCOLORSCREEN $GSOPTS" ;; 2) GSOPTS="-dMaxBitMap=500000000 $GSOPTS" ;; esac # # Validate media code # case "$MEDIA" in 0|auto) MEDIA=0;; 1|plain) MEDIA=1;; 2|preprinted) MEDIA=2;; 3|letterhead) MEDIA=3;; 4|gratrans*) MEDIA=4;; 5|prepunched) MEDIA=5;; 6|labels) MEDIA=6;; 7|bond) MEDIA=7;; 8|recylcled) MEDIA=8;; 9|color) MEDIA=9;; 10|cardstock) MEDIA=10;; 11|heavy) MEDIA=11;; 12|envelope) MEDIA=12;; 13|light) MEDIA=13;; 14|tough) MEDIA=14;; [0-9]*) ;; *) error "Unknown media code $MEDIA";; esac # # Validate source (InputSlot) code # case "$SOURCE" in 1|tray1) SOURCE=1;; 4|manual) SOURCE=4;; 7|auto) SOURCE=7;; [0-9]*) ;; *) error "Unknown source code $SOURCE";; esac # # Validate Duplex code # case "$DUPLEX" in 1|off|none) DUPLEX=1;; 2|long*) DUPLEX=2;; 3|short*) DUPLEX=3;; [0-9]*) ;; *) error "Unknown duplex code $DUPLEX";; esac # # Validate Resolution # case "$RES" in 600x600) ;; 1200x600) ;; 2400x600) ;; *) error "Illegal resolution $RES";; esac # # Figure out the paper dimensions in pixels/inch, and set the # default clipping region. # set_clipping() { ulx=$1; uly=$2 lrx=$3; lry=$4 # Set clipping region if it isn't already set if [ "$CLIP_UL" = "" ]; then case "$RES" in 600x600) ulx=`expr $ulx / 2`;; 2400x600) ulx=`expr $ulx \* 2`;; esac CLIP_UL="-u ${ulx}x${uly}" fi if [ "$CLIP_LR" = "" ]; then case "$RES" in 600x600) lrx=`expr $lrx / 2`;; 2400x600) lrx=`expr $lrx \* 2`;; esac CLIP_LR="-l ${lrx}x${lry}" fi } case "$PAPER" in Custom*) #%%BeginFeature: *CustomPageSize True #216 #360 #0 #0 #0 #pop pop pop pop pop TMPFILE=/tmp/cus$$ cat >$TMPFILE exec <$TMPFILE XDIM=`head -n 1000 $TMPFILE | sed -n '/CustomPageSize/{n;p;}'` case "$XDIM" in ""|0*) rm -f $TMPFILE error "Custom page size XDIM != 1-99999" ;; esac XDIM=`dc -e "$XDIM 1200* 72/p"` YDIM=`head -n 1000 $TMPFILE | sed -n '/CustomPageSize/{n;n;p;}'` case "$YDIM" in ""|0*) rm -f $TMPFILE error "Custom page size YDIM != 1-99999" ;; esac YDIM=`dc -e "$YDIM 600* 72/p"` PAPER=1; paper=letter; set_clipping 2 100 2 100 ;; 1|letter) PAPER=1; paper=letter; XDIM="10200"; YDIM="6600" set_clipping 140 100 140 100 ;; 5|legal) PAPER=5; paper=legal; XDIM="10200"; YDIM="8400" set_clipping 140 100 140 100 ;; 7|executive) PAPER=7; paper=executive; XDIM="8700"; YDIM="6300" set_clipping 140 100 140 100 ;; 9|a4|A4) PAPER=9; paper=a4; XDIM="9920"; YDIM="7014" set_clipping 160 100 160 100 ;; 11|a5|A5) PAPER=11; paper=a5; XDIM="6992"; YDIM="4960" set_clipping 140 100 140 100 ;; 13|b5jis|B5JIS) PAPER=13; paper=b5; XDIM="8598"; YDIM="6070" set_clipping 140 100 140 100 ;; *) error "Unimplemented paper code $PAPER";; esac PAPERSIZE="-sPAPERSIZE=$paper"; case "$RES" in 600x600) XDIM=`expr $XDIM / 2`;; 1200x600) ;; 2400x600) XDIM=`expr $XDIM \* 2`;; esac DIM="${XDIM}x${YDIM}" # # Filter thru psnup if N-up printing has been requested # case $NUP in [234689]|1[024568]) PREFILTER="nup";; *) PREFILTER=cat;; esac # # Overload -G. If the file name ends with ".icm" or ".ICM" # then convert the ICC color profile to a Postscript CRD, # then prepend it to the users job. Select the intent # using the -I option. # create_crd() { # # Create a Postscript CRD # ICC2PS=$PREFIX/bin/foo2zjs-icc2ps if [ -x $ICC2PS ]; then $ICC2PS -o $GAMMAFILE -t$INTENT > $ICCTMP.crd.ps 2>$ICCTMP.log \ || error "Problem converting .ICM file to Postscript" cat > $ICCTMP.usecie.ps <<-EOF %!PS-Adobe-3.0 <>setpagedevice EOF cat > $ICCTMP.selcrd.ps <<-EOF /Current /ColorRendering findresource setcolorrendering EOF GAMMAFILE="$ICCTMP.usecie.ps $ICCTMP.crd.ps $ICCTMP.selcrd.ps" else GAMMFILE= fi } if [ $DEBUG -gt 0 ]; then ICCTMP=/tmp/icc else ICCTMP=/tmp/icc$$ fi case "$GAMMAFILE" in *.icm|*.ICM|*.icc|*.ICC) # # Its really an .ICM file, not a gamma file. # # The file can be a full path name, or the name of a file in $SHARE/icm/ # if [ "$COLOR" = "" ]; then GAMMAFILE= elif [ -r "$GAMMAFILE" ]; then create_crd elif [ -r "$SHARE/icm/$GAMMAFILE" ]; then GAMMAFILE="$SHARE/icm/$GAMMAFILE" create_crd else GAMMAFILE= fi ;; esac # # Use a Well Tempered Screen in quality mode 2. # from Karl Putland # # NOTE from Rick: Karl abandoned this approach. # create_wts() { # # Screen frequencies # C_FREQ="120" M_FREQ="123.33" Y_FREQ="126.85" K_FREQ="143.22" case "$RES" in 600x600) MUL=0.50;; 1200x600) MUL=0.75;; 2400x600) MUL=1.00;; *) MUL=0.50;; esac cat > $ICCTMP.wts.ps <<-EOF %!PS-Adobe-3.0 << /UseWTS true >> setuserparams << /HalftoneType 5 /Cyan << /AccurateScreens true /HalftoneType 1 /SpotFunction { % 180 mul cos exch 180 mul cos add 2 div abs exch abs 2 dup add 0.75 le { 2 exp exch 2 exp add 1 exch sub } { 2 dup add 1.23 le { exch 0.76 mul add 1 exch sub } { 1 sub 2 exp exch 1 sub 2 exp add 1 sub } ifelse } ifelse } /TransferFunction {1 exp} /Frequency $C_FREQ $MUL mul /Angle 98 >> /Magenta << /AccurateScreens true /HalftoneType 1 /SpotFunction { % 180 mul cos exch 180 mul cos add 2 div abs exch abs 2 dup add 0.75 le { 2 exp exch 2 exp add 1 exch sub } { 2 dup add 1.23 le { exch 0.76 mul add 1 exch sub } { 1 sub 2 exp exch 1 sub 2 exp add 1 sub } ifelse } ifelse } /TransferFunction {0.45 exp} /Frequency $M_FREQ $MUL mul /Angle 51.5 >> /Yellow << /AccurateScreens true /HalftoneType 1 /SpotFunction { % 180 mul cos exch 180 mul cos add 2 div abs exch abs 2 dup add 0.75 le { 2 exp exch 2 exp add 1 exch sub } { 2 dup add 1.23 le { exch 0.76 mul add 1 exch sub } { 1 sub 2 exp exch 1 sub 2 exp add 1 sub } ifelse } ifelse } /TransferFunction {0.45 exp} /Frequency $Y_FREQ $MUL mul /Angle 27 >> /Black << /AccurateScreens true /HalftoneType 1 /SpotFunction { % 180 mul cos exch 180 mul cos add 2 div abs exch abs 2 dup add 0.75 le { 2 exp exch 2 exp add 1 exch sub } { 2 dup add 1.23 le { exch 0.76 mul add 1 exch sub } { 1 sub 2 exp exch 1 sub 2 exp add 1 sub } ifelse } ifelse } /TransferFunction {0.60 exp} /Frequency $K_FREQ $MUL mul /Angle 75 >> /Default << /AccurateScreens true /HalftoneType 1 /SpotFunction { % 180 mul cos exch 180 mul cos add 2 div abs exch abs 2 dup add 0.75 le { 2 exp exch 2 exp add 1 exch sub } { 2 dup add 1.23 le { exch 0.76 mul add 1 exch sub } { 1 sub 2 exp exch 1 sub 2 exp add 1 sub } ifelse } ifelse } /TransferFunction {0.45 exp} /Frequency $Y_FREQ $MUL mul /Angle 27 >> >> sethalftone EOF GAMMAFILE="$GAMMAFILE $ICCTMP.wts.ps" } if [ "$COLOR" != "" -a "$QUALITY" = 2 ]; then create_wts fi # # Figure out USERNAME # if [ "$LPUSER" != "" ]; then USER="$LPUSER@$LPHOST" else USER="" fi # # Main Program, just cobble together the pipeline and run it # # The malarky with file descriptors 1 and 3 is to avoid a bug in # (some versions?) of Ghostscript where Postscript's stdout gets # intermingled with the printer drivers output, resulting in # corrupted image data. # GS="$GSBIN -q -dBATCH -dSAFER -dQUIET -dNOPAUSE" $PREFILTER \ | ($GS $PAPERSIZE -g$DIM -r$RES $GSDEV $GSOPTS \ -sOutputFile="|cat 1>&3" $GAMMAFILE - >/dev/null 2>/dev/null) 3>&1 \ | dbgcmd foo2oak -r$RES -g$DIM -p$PAPER -m$MEDIA -n$COPIES -d$DUPLEX -s$SOURCE \ $COLOR -b$BPP $CLIP_UL $CLIP_LR $CLIP_LOG \ -J "$LPJOB" -U "$USER" \ $BC $AIB $COLOR2MONO -D$DEBUG # # Log the command line, for debugging and problem reports # if [ $DEBUG = 0 -a -x /usr/bin/logger ]; then logger -t "$BASENAME" -p lpr.info -- \ "gs $PAPERSIZE -g$DIM -r$RES $GSDEV $GSOPTS" logger -t "$BASENAME" -p lpr.info -- \ "foo2oak -r$RES -g$DIM -p$PAPER -m$MEDIA \ -n$COPIES -d$DUPLEX -s$SOURCE $COLOR -b$BPP $CLIP_UL $CLIP_LR $CLIP_LOG \ $BC $AIB $COLOR2MONO" fi # # Remove cruft # if [ $DEBUG -eq 0 ]; then for i in crd.ps log usecie.ps selcrd.ps wts.ps do file="$ICCTMP.$i" [ -f $file ] && rm -f $file done [ -f "$TMPFILE" ] && rm -f $TMPFILE fi exit 0