I'm trying to write a number of gs commands for server-side use. The user-provided PDF/JPEG files, I have to work with cannot be assumed to be safe (broken or even malicious files could be provided). Therefore, I'm trying to write all of my Ghostscript commands with -dSAFER, to guarantee at least a basic level of security.
Unfortunately, -dSAFER appears to be incompatible with certain gs commands. Take for example the following command:
# count number of pages in PDF
gs -dQUIET -dBATCH -dNOPAUSE -dNOSAFER -dNODISPLAY \
-c "(input.pdf) (r) file runpdfbegin pdfpagecount = quit"
How would you re-write this command with -dSAFER? The command fails if I just add -dSAFER, because gs can't read the file input.pdf (which is what I expect). How do I tell gs that is permitted to read input.pdf, but nothing else? Maybe there's a way to permit reading of files only from certain directories?
Here's a second example command:
# convert JPEG to single-page PDF
gs -dQUIET -dBATCH -dNOPAUSE -dNOSAFER \
-sDEVICE=pdfwrite -dCompatibilityLevel=1.5 -dPDFSettings=/printer \
-sColorConversionStrategy=Gray -dProcessColorModel=/DeviceGray \
-sOutputFile=output.pdf \
viewjpeg.ps \
-c "(input.jpg) << /PageSize 2 index viewJPEGgetsize 2 array astore >> setpagedevice viewJPEG"
This command has exactly the same problem as the first one. How do I re-write this with -dSAFER?
Please include a link to the relevant documentation in your answer if you think that -dSAFER is really not needed for my commands.
You can add directories to the search list using -I, IIRC any such directory is permitted to be read. For the current directory you can also use -P- and -P.
See Use.htm in the ghostpdl/doc directory.
However, even if adding the current directory allows you to read the file, this will soon stop working with -dSAFER anyway. There's an ongoing programme to 'harden' the interpreter when -dSAFER is set by hiding/remobing any non-standard operators especially if there's any possibility they could be misused.
Your proposed usage is, simply, incompatible with -dSAFER. The commands you are using will almost certainly be specifically prohibited because they are inherently unsafe. Essentially by messing about inside PDF files like that, your PostScript program is unsafe.
Of course, you know that your PostScript program is safe, and since you are not executing any part of the PDF, the PDF is also safe. The PDF would only be unsafe if you attempted to actually execute the contents, which your program doesn't do. It simply opens the file reads the Pages tree, and tells you the value associated with the Count key.
So you don't need to set -dSAFER in this particular example anyway. However any such program which did execute the PDF content (eg by rendering any part of it, or sending it to the pdfwrite device) would not be safe.
Your second example also doesn't need SAFER, since a JPEG can't contain code to access the disk.
Related
well I've given up. I don't think I understand how GS works... as far as I understand GS replaces all fonts that are not embedded and should not touch already embedded ones? why is it replacing them? I have a pdf file that contains 2 embedded fonts and 1 not embedded (ArialMT).
I'm using command:
"gswin64c.exe -I "C:/Program Files/gs/gs9.56.1/Resource/Init" -sFONTMAP="Fontmap.GS" -dNOSAFER -dPDFACompatibilityPolicy=1 -sColorConversionStrategy=LeaveColorUnchanged -dBATCH -dNOPAUSE -sDEVICE="pdfwrite" -dAutoRotatePages=/None -dPDFA=3 -sOutputFile="pdfa.pdf" "original.pdf"
all I get with this command is this error:
GPL Ghostscript 9.56.1: Actual TT subtable offset xxxxx differs from one in the TT header yyyy. (multiple ones like this)
The following errors were encountered at least once while processing this file:
error executing PDF token
**** This file had errors that were repaired or ignored.
**** The file was produced by:
**** >>>> StreamServe Communication Server 16.6.1 GA Build 319 (64 bit) <<<<
**** Please notify the author of the software that produced this
**** file that it does not conform to Adobe's published PDF
**** specification.
the output is a pdf without ANY fonts...
is there any way to force GS not to replace font if it wasn't found on the system?
why is it replacing ArialMT with NimbusSans-Regular even though I have declared a specific path to ArialMT in my FontMap.GS file?
I'd rather not share this pdf file as it contains sensitive customer data.
(osadzony podzestaw=embedded subset)
Ghost Script substitution will require embeddable fonts on windows those are usually stored in C:\Windows\Fonts
Thus if font substitution was simple (without look-up) your command could be simplified
gswin64c.exe -sFONTPATH="C:\Windows\Fonts" -dNOSAFER -sDEVICE=pdfwrite -dNEWPDF=false -dPDFA=3 -dPDFACompatibilityPolicy=1 -sColorConversionStrategy=LeaveColorUnchanged -dAutoRotatePages=/None -o"pdfa.pdf" "original.pdf"
you need to add -dNEWPDF=false Since to include additional mapping you add -I "C:/Program Files/gs/gs9.56.1/Resource/Init" -sFONTMAP=Fontmap.gs
Thus the following should be a startpoint
gswin64c.exe -sFONTPATH="C:\Windows\Fonts" -I "C:/Program Files/gs/gs9.56.1/Resource/Init" -sFONTMAP=Fontmap.gs -dNOSAFER -sDEVICE=pdfwrite -dNEWPDF=false -dPDFA=3 -dPDFACompatibilityPolicy=1 -sColorConversionStrategy=LeaveColorUnchanged -dAutoRotatePages=/None -o"pdfa.pdf" "original.pdf"
It will not remove warnings using a PDF file from the same developer, the difference was now there is no mention of Nimbus, but the substitutions should be better/fuller as the warning messages verified the fonts were eventually applied from windows
Note the file is smaller although the fonts are embedded, and in side by side comparison they look the same.
GPL Ghostscript 9.56.1: PDFA doesn't allow images with Interpolate true.
and
The following errors were encountered at least once while processing this file:
missing white space after number
error executing PDF token
**** This file had errors that were repaired or ignored.
**** Please notify the author of the software that produced this
**** file that it does not conform to Adobe's published PDF
**** specification.
from their report.
If I save the file from Acrobat the file size drops but the same issues reside
i use GS with this command line
gswin32c.exe -sDEVICE=tiffg4 -dSAFER -dBATCH -dNOPROMPT -sPAPERSIZE=a4 -dFIXEDMEDIA -dPDFFitPage -dNOPAUSE -r600 -g6120x7920 -dPrinted=false -sOutputFile="C:\test\test_%d.tif c:\test\xyz.pdf
That works fine, but it always start with the "1" value, so the output is "test_1.tif".
How do i need to modify the comanndline, to force GS to start with another value, e.g. 7.
so GS convert the multipage PDF "xyz.pdf" to singlepage tiff like "test_7.tif, test_8.tif" and so on.
background:
i have several pdf and the naming of the pdf is allways different. but i want one ongoing name for the tif file which allways begin with "test" in this case and the incremental value for each pdf page.
also my first pdf extract have to be the first tiff files, then the 2nd PDF file extract have to append and so on.
hopefully its a litte bit clear what i need ;)
BR Ralf
The %d convention is simply a C printout format and as mentioned in KenS comment cannot be "offset"
see https://www.ghostscript.com/doc/current/Use.htm#One_page_per_file
but there are workarounds mentioned in
How to set printf %d offset for Ghostscript?
However they are perhaps not the most efficient, but may help in some cases, just beware the comments below them.
The simplest way I will alter the range is to apply a preset such as
1%d to produce 10 11 12..., or
2%02d = 201 202 ...
Again you are limited to the first page will always be ###1 and if you need it to start at ###5 then you need to rename all files post production. That can often be easily scripted depending how well you prepare the desired names.
I am creating a pdf file using ghostscript 9.15. I have been using ghostscript for about 5 years and haven’t encountered any serious issues till this week.
Essentially I am running the query below….
“c://distiller/exes/gswin32c.exe" -sDEVICE="pdfwrite" -dNOPAUSE -dBATCH -dNOSAFER -dQUIET -sFONTPATH="C:/Windows/Fonts" -sOUTPUTFILE="C:\distiller\test.pdf" "C:\ExactDistiller \example.ps"
and I get the error below
Current allocation mode is local Last OS error: No such file or
directory Current file position is 197197 GPL Ghostscript 9.15:
Unrecoverable error, exit code 1
I am getting the error “No such file or directory” but I have checked every file path and checked every font is installed and all seems fine but still no luck. I just want to know is there a way of finding out what file / directory is causing the issue?
Well the first thing I would do is not set -dQUIET, turning off information isn't a good way to debug a problem. Not setting -dBATCH and -dNOPAUSE might be helpful too as it might show you more of what is going on. Note that -dNOSAFER is in fact the default, you don't need to set that unless you have previously set your environment to include -dSAFER
In short, when trying to debug the problem, simplify it as far as possible, don't set any switches unless you know you need them, or they contribute to the problem.
You could then paste the stdout transcript which might shed some illumination.
Secondly, your directory appears to contain a trailing space before the separator "c:\ExactDistiller \example.ps", is that correct ? A 'No such file or directory' error will be thrown (without a PostScript error) if you get the input filename incorrect.
If there is a PostScript error revealed when you stop issuing -dQUIET then you can paste it in your original question (by editing it) and I'll take a look. It may be necessary to see your example.ps file, depending on what that reveals.
I have created a small script to run my PS file through the windows printer driver for printout.
I use this code:
echo mark /NoCancel true /BitsPerPixel 4 /OutputFile (%printer%%PNAME%) /UserSettings ^<^</DocumentName (%MYDOCNAME%) ^>^> (mswinpr2) finddevice putdeviceprops setdevice>setup.ps
gswin32c -dNOPAUSE -dBATCH -r84 setup.ps %1
The script is creating a setup.ps file as recommended by the gs documentation for the mswinpr2 driver.
It looks like this:
mark
/NoCancel true
/BitsPerPixel 4
/OutputFile (Windows printer name)
/UserSettings
<<
/DocumentName (the text for the job in the spooler queue)
>>
(mswinpr2)
finddevice
putdeviceprops
setdevice
%printer% resolves to the empty string on my machine.
%PNAME% is the name of the windows printer, "C364PS" for me.
The %printer%%PNAME% is taken from the documentation to give the desired target printer. To stay with the example printer it will resolve to C364PS
gs is then called as
gswin32c -dNOPAUSE -dBATCH -r84 setup.ps <name of desired ps file here>
This works as expected, regarding the printed result. But I want a silent printout, since I have chosen the printer before. Whatever I choose for %PNAME%, it will always pop up the "select printer" dialog.
I am running Windows 8.1 and tried gs 8.70 and 9.19.
If I add /QueryUser 3 to the setup.ps, the printout starts without further confirmation of the printer, but then it will only print on the default printer, not on the one selected in the /OutputFile.
What am I missing?
Update: I have checked this question's result, but it does not work for me, dialog keeps popping up: https://superuser.com/questions/807027/how-to-print-with-ghostscript-in-silent-mode
Update 2: I have now (as requested) tried a commandline, with the same result. I also tried without the %printer%, no difference here:
gswin32c -dNOPAUSE -dBATCH -dNOPROMPT -dNOQUERY -sOutputFile="%printer%C364SeriesPCL" -r84 setup.ps 151008172940#123#000001#000001#PR_CCCC_Vertragspruef_4#CCCC_CAAA.358636.ps
setup.ps is this, no linebreaks have been added:
mark /NoCancel true /BitsPerPixel 4 /OutputFile (C364SeriesPCL) /UserSettings <</DocumentName (151008172940#123#000001#000001#PR_CCCC_Vertragspruef_4#CCCC_CAAA.358636) >> (mswinpr2) finddevice putdeviceprops setdevice
Solution:
The string %printer% is actually a literal in the setup.ps /OutputFile () or on the commandline. So changing the setup.ps worked:
mark /NoCancel true
/BitsPerPixel 4
/OutputFile (%printer%C364SeriesPCL)
/UserSettings <<
/DocumentName (151008172940TBS000001000001PR_CONT_Vertragspruef_4CONT_CONT.358636)
>>
(mswinpr2)
finddevice
putdeviceprops
setdevice
This way, the printer is found. I tried to copy the behavior with a commandline switch -sOutputFile but was not able to make the dialog go away without the setup.ps - I tried %%printer%%, but to no avail. As I am fine with the setup.ps, I am not following that further.
The root of my problem was, that the ghostscript documentation is correct, nevertheless, easily misunderstood here. Especially in the context of windows, it would not hurt to state explicitely, that %printer% is actually no env-variable, but really a string literal, that must be present in the output filename.
-sOutputFile="%printer%printer_name"
Specifies which printer should be used. The printer_name should be typed exactly as it appears in the Printers control panel, including
spaces.
To really answer my initial question. The commandline script must be changed, to escape the % signs in the %printer% literal:
echo mark /NoCancel true /BitsPerPixel 4 /OutputFile (%%printer%%%PNAME%) /UserSettings ^<^</DocumentName (%MYDOCNAME%) ^>^> (mswinpr2) finddevice putdeviceprops setdevice>setup.ps
gswin32c -dNOPAUSE -dBATCH -dNOPROMPT -r84 setup.ps %1
This works as initially planned.
I've moved this to an answer, because there is insufficient room in the comments.
So, what I would normally expect to see as a (simple) command line for this would be:
gswin32c -dNOPAUSE -dBATCH -dNOPROMPT -dNOQUERY -sOutputFile="%printer%C364SeriesPCL" 151008172940#123#000001#000001#PR_CCCC_Vertragspruef_4#CCCC_CAAA.358636.ps
Your command line includes -r84 which would normally set the resolution to 84 dpi, if that actually gets honoured you are going to print a horribly low resolution image of the PostScript, I very much doubt you really want that.
On top of that, you also are still sending setup.ps before your actual PostScript program. The problem with that is that setup.ps overrides the values you set on the command line. So your -sOutputFile="%printer%C364SeriesPCL" is overridden by the contents of setup.ps where you define /OutputFile (C364SeriesPCL)
Now, as I was suggesting earlier, your problem here is that the correct syntax for a printer is "%printer%printer name" and what you have in setup.ps is lacking the %printer%. I would imagine the reason that %printer% is missing is because you put it in a batch file and %printer% is being treated as an environment variable. Since it isn't set, it gets replaced by nothing.
So, I would suggest that you start off by using the command line you gave, but NOT including setup.ps and see what that does. If that works, then you know what the problem is. In order to use %printer% in a batch file you need to 'escape' the '%' which means you will need (I think) %%printer%%
Given that you have a PostScript printer (C364SeriesPS) why don't you just send the original PostScript file ? What you are doing here is having Ghostscript render the PostScript to an image (a Windows Bitmap in fact) which it then passes to the printing system, which will send the bitmap to the printer. This is slow, and involves shuffling a lot of data around, when you could just send the PostScript straight to the printer.
as a ruby newb i've been on a little ghost hunt that you might be of some help
I read a lot and was told the best way to get these sneaky fellows was using a script : ghostscript.
I'm trying to execute the ghostscript command that i run in a virtual printer, but in the context of a ruby (shoes) file :
My command is :
C:\Programas\gs\gs9.05\bin\gswin64c.exe -IC:\Programas\gs\gs9.05\lib;C:\Programas\gs\fonts -sDEVICE=pdfwrite -r300 -dNOPAUSE -dSAFER -sPAPERSIZE=a4 -sOutputFile=c:\tempRep\temp.pdf -
If i just put this command inside a batch file, and set this batch as the program to call within to port redirect on the virtual printer, it goes just fine, writing the temp.pdf file. The problem with this solution are actually two :
Not very DRY
the exe file doesn't get executed
my filecreate.bat
C:\Programas\gs\gs9.05\bin\gswin64c.exe -IC:\Programas\gs\gs9.05\lib;C:\Programas\gs\fonts -sDEVICE=pdfwrite -r300 -dNOPAUSE -dSAFER -sPAPERSIZE=a4 -sOutputFile=c:\tempRep\temp.pdf -
c:\tempRep\myapp.exe
So, if it's not DRY and bats don't seem to be helping, there is no point looking for ghosts here. We all know that to catch a ghost, it must be DRY !
So I headed towards Rghost : Reveal ghosts is the true meaning.
The context where I call it:
My shoes app source:
Shoes.setup do
gem 'rghost'
end
require 'RGhost'
RGhost::Config::GS[:path]= 'C:\\Programas\\gs\\gs9.05\\bin\\gswin64c.exe'
doc=Document.new
doc.render :raw => "-sDEVICE=pdfwrite -r300 -dNOPAUSE -dSAFER -sPAPERSIZE=a4 -sOutputFile=c:\tempRep\temp.pdf -"
I'm starting to feel chilly, but no ghost file is showing up...
Any ideas on how to catch this one?
I am also considering using something like
system("C:\Programas\gs\gs9.05\bin\gswin64c.exe -IC:\Programas\gs\gs9.05\lib;C:\Programas\gs\fonts -sDEVICE=pdfwrite -r300 -dNOPAUSE -dSAFER -sPAPERSIZE=a4 -sOutputFile=c:\tempRep\temp.pdf -")
but it just doesn't seem to work :S...What might i be doing wrong?