|
|
% Copyright (C) 2001-2023 Artifex Software, Inc.
% All Rights Reserved.
%
% This software is provided AS-IS with no warranty, either express or
% implied.
%
% This software is distributed under license and may not be copied,
% modified or distributed except as expressly authorized under the terms
% of the license contained in the file LICENSE in this distribution.
%
% Refer to licensing information at http://www.artifex.com or contact
% Artifex Software, Inc., 39 Mesa Street, Suite 108A, San Francisco,
% CA 94129, USA, for further information.
%
% Allow the interpreter to encapsulate EPS files, to recognize MS-DOS
% EPSF file headers, and skip to the PostScript section of the file.
% Encapsulate EPS files and optionally resize page or rescale image.
% To display an EPS file cropped to the bounding box:
% gs -dEPSCrop file.eps
% To display an EPS file scaled to fit the page:
% gs -dEPSFitPage file.eps
% To display a file without EPS encapsulation:
% gs -dNOEPS file.ps
% When starting to process an EPS file, state is 0.
% After %%BoundingBox processed, state is 1 if OK or 2 if cropped.
% After %%HiResBoundingBox processed, state is 3 if OK or 4 if cropped.
% After %%EndComments processed, state is 5.
/EPSBoundingBoxState 5 def/EPSBoundingBoxString () def % set if either BoundingBox is seen (even if invalid)
/EPSBoundingBoxSetState { //systemdict /EPSBoundingBoxState 3 -1 roll .forceput} .forcebind odef % .forceput must be bound and hidden
% Parse 4 numbers for a bounding box
/EPSBoundingBoxParse { % (llx lly urx ury) -- llx lly urx ury true OR false
mark exch token {exch token {exch token {exch token {exch pop} if} if} if} if counttomark 4 eq { 5 -1 roll pop % remove mark
//true } { cleartomark //false } ifelse} .internalbind odef
% Crop the page to the BoundingBox
/EPSBoundingBoxCrop { % llx lly urx ury --
EPSDEBUG { (gs_epsf.ps: Setting pagesize from EPS bounding box\n) print flush } if exch 3 index sub exch 2 index sub % stack: llx lly urx-llx ury-lly
<< /PageSize [ 5 -2 roll ] >> setpagedevice neg exch neg exch translate} .internalbind odef
% Rescale, translate and rotate to fit the BoundingBox on the page
/EPSBoundingBoxFitPage { % llx lly urx ury --
EPSDEBUG { (gs_epsf.ps: Rescaling EPS to fit page\n) print flush } if clippath pathbbox newpath % ellx elly eurx eury pllx plly purx pury
EPSDEBUG { (Page Coordinates: LLX: ) print 3 index =print (, LLY: ) print 2 index =print (, URX: ) print 1 index =print (, URY: ) print dup = flush } if % Convert box corners to coordinates of the center and box sizes
2 { % loop doing the page coordinates, the the EPS bbox coordinates
3 -1 roll exch % ... llx urx lly ury
2 { % loop doing Y then X coordnates
2 copy exch sub % ... llx urx lly ury ury-lly
3 1 roll % ... llx urx ury-lly lly ury
add 2 div % ... llx urx ury-lly (lly+ury)/2
4 2 roll % ... ury-lly (lly+ury)/2 llx urx
} repeat 8 4 roll } repeat % edx, edy = EPS dimension X and Y, ecx, ecy = EPS Center X and Y.
% pdx and pcx, etc, are for the Page values.
% edx ecx edy ecy pdx pcx pdy pcy
% Move the origin to the center of the printable area.
3 -1 roll exch % edx ecx edy ecy pdx pdy pcx pcy
translate % edx ecx edy ecy pdx pdy
% Find orientation of the best fit. Square pages or files don't rotate.
2 copy sub % edx ecx edy ecy pdx pdy pdx-pdy
EPSDEBUG { (pdx: ) print 2 index =print (, pdy: ) print 1 index =print (, pdx-pdy: ) print dup = flush } if 6 index 5 index sub EPSDEBUG { (edx: ) print 7 index =print (, edy: ) print 5 index =print (, edx-edy: ) print dup = flush } if mul % edx ecx edy ecy pdx pdy (pdx-pdy)*(edx-edy)
EPSDEBUG { (product: ) print dup = flush } if 0 lt { 90 rotate exch } if
% Scale to fit in the most restricting direction.
4 -1 roll div % edx ecx ecy pdx pdy/edy
exch 5 -1 roll div % ecx ecy pdy/edy pdx/edx
//.min exec dup scale % ecx ecy
% Center the document
neg exch neg exch translate
} .internalbind odef
/EPSBoundingBoxProcess { % (llx lly urx ury) state --
% The following 'lt' check prioritzies HiResBoundingBox over BoundingBox
% even if HiResBoundingBox occurs first in the EPS file.
//systemdict /EPSBoundingBoxState get 1 index lt { % save the BBoxString for possible FitPage when EndComments is seen
exch dup currentglobal //true setglobal exch dup length string copy //systemdict /EPSBoundingBoxString 3 -1 roll .forceput setglobal EPSBoundingBoxParse { //systemdict /EPSCrop known { EPSBoundingBoxCrop } { //systemdict /EPSFitPage known not { % Warn if some of the EPS file will be clipped
clippath pathbbox newpath { % context for exit
5 -1 roll lt { 6 { pop } repeat //true exit } if 4 -1 roll lt { 4 { pop } repeat //true exit } if 3 -1 roll gt { 2 { pop } repeat //true exit } if exch gt { //true exit } if //false exit } loop QUIET not and /EPSBoundingBoxState .systemvar 1 and 1 eq and { (\n **** Warning: Some of the BoundingBox for the EPS file will be clipped.) = ( Use -dEPSCrop or -dEPSFitPage to avoid clipping.\n) = flush 1 add } if } { pop pop pop pop } ifelse } ifelse EPSBoundingBoxSetState } { % improperly formed BoundingBox string.
QUIET not { (\n **** Warning: BoundingBox values are invalid and will be ignored: ') print EPSBoundBoxString print (') = flush } if pop % state
} ifelse } { pop pop } ifelse} .internalbind odef
% Perform anchorsearch on the strings in the array until a match is found.
/anchorsearchforany { % haystack [needle1 ...] --> post needle true
% --> haystack false
false 3 1 roll % false haystack [...]
{ % false haystack needle
dup 3 1 roll % false needle haystack needle
anchorsearch { % false needle post needle
pop % false needle post
3 1 roll % post false needle
exch not exch % post true needle
exit } { % false needle haystack
exch pop % false haystack
} ifelse } forall exch % haystack false | post needle true
} .internalbind def
/ProcessEPSComment { % file comment -- file comment
/EPSBoundingBoxState .systemvar 3 lt { dup (%%BoundingBox:) anchorsearch { pop EPSDEBUG { (gs_epsf.ps: found %%BoundingBox\n) print flush } if 1 EPSBoundingBoxProcess } { (%%HiResBoundingBox:) anchorsearch { pop EPSDEBUG { (gs_epsf.ps: found %%HiResBoundingBox\n) print flush } if 3 EPSBoundingBoxProcess } { pop % Not interested in this DSC comment
} ifelse } ifelse } if /EPSBoundingBoxState .systemvar 5 lt { dup (%%DocumentCustomColors:) anchorsearch { pop [ exch { { token not { exit } if dup type /stringtype ne { stop } if dup (atend) eq { stop } if exch } loop { counttomark 2 add index dup (123) .peekstring not { stop } if (%%+) eq { dup (123) readstring pop pop 256 string readline pop cvx exec } { pop exit } ifelse } loop } stopped { cleartomark } { counttomark 0 gt { currentpagedevice /MaxSeparations get 4 gt { ] << /SeparationColorNames 3 -1 roll >> setpagedevice } { cleartomark } ifelse } { cleartomark } ifelse } ifelse } { {(%%EndComments) (%%BeginProlog) (%%BeginSetup)} anchorsearchforany { EPSDEBUG { (EPSComment processing finished, encountered: ) print dup = } if pop pop % discard the strings from the anchorsearch
% We may have seen BoundingBox or HiResBounfingBox. If so and if EPSFitPage
% is set, then we do the transformation here to scale and center the page,
% rotating if needed (and AllowFitPageRotation is true -- the default.)
//systemdict /EPSFitPage known //systemdict /EPSBoundingBoxState get 0 gt and { EPSBoundingBoxString EPSBoundingBoxParse { EPSBoundingBoxFitPage } if } if % Ignore any following comments
5 EPSBoundingBoxSetState } { pop % Not %%EndComments -- ignore it
} ifelse } ifelse } if} .internalbind def
% Install EPS handler for DSC comments, which we do later
/EPSBoundingBoxInit { systemdict /NOEPS known not { % Merge ProcessEPSComment with existing handler
//ProcessEPSComment /exec load currentuserparams /ProcessDSCComment get dup //null eq {pop {pop pop}} if /exec load 4 array astore cvx readonly << /ProcessDSCComment 3 -1 roll >> setuserparams } if} .internalbind odef
/.runNoEPS /run load def
/.runEPS { % file OR string --
.updatematrices /runEPS_save save def /runEPS_dict_count countdictstack def /runEPS_op_count count 2 sub def /runEPS_page_count .currentshowpagecount not {0} if def 0 EPSBoundingBoxSetState //.runNoEPS .currentshowpagecount not {0} if runEPS_page_count sub 0 eq { /showpage load exec } if count runEPS_op_count sub {pop} repeat countdictstack runEPS_dict_count sub {end} repeat runEPS_save restore} .internalbind odef
/run { % file OR string --
dup type /filetype ne { (r) file } if dup (%!PS-Adobe-) .peekstring { (%!PS-Adobe-) eq { dup (%!PS-Adobe-X.X EPSF-X.X) .peekstring { (EPSF) search { pop pop pop EPSDEBUG {(runEPS: Found EPS\n) print flush} if systemdict /NOEPS known { cvx //.runNoEPS } { cvx .runEPS } ifelse } { EPSDEBUG {(runEPS: Normal DSC\n) print flush} if pop cvx //.runNoEPS
} ifelse } { EPSDEBUG {(runEPS: Short DSC\n) print flush} if pop cvx //.runNoEPS } ifelse } { EPSDEBUG {(runEPS: Not DSC\n) print flush} if cvx //.runNoEPS } ifelse } { EPSDEBUG {(runEPS: Short non-DSC\n) print flush} if pop cvx //.runNoEPS } ifelse} .internalbind odef
% Handle DOS EPS files.
/.runnoepsf /run load def/.epsfheader <C5D0D3C6> def/run { dup type /filetype ne { (r) file } if % Check for MS-DOS EPSF file (see Red Book p. 729).
dup ( ) .peekstring { .epsfheader eq { dup ( ) readstring exch pop } { //false } ifelse } { pop //false } ifelse % Stack: file true/false
{ % This block is executed if the file is MS-DOS EPSF.
% Build up the little-endian byte offset and length.
2 { 1 0 4 { 2 index read not { pop exit } if % if EOF, let error happen
2 index mul add exch 256 mul exch } repeat exch pop exch } repeat % Stack: offset length file
% Use flushfile to skip quickly to the start of the
% PostScript section.
dup 4 -1 roll 12 sub () /SubFileDecode filter flushfile % Now interpret the PostScript.
exch () /SubFileDecode filter cvx run } { //.runnoepsf } ifelse } odef
% rebind .runstdin to use redefined run
userdict begin/.runstdin { { (%stdin) run } execute0} .internalbind defend
% undefine things defined in this file and not referenced elsewhere
[ /.runNoEPS /.runnoepsf /.runEPS /EPSBoundingBoxSetState /EPSBoundingBoxString /EPSBoundingBoxCrop /EPSBoundingBoxFitPage /EPSBoundingBoxParse /EPSBoundingBoxProcess /ProcessEPSComment] currentdict .undefinternalnames
|