You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

377 lines
12 KiB

1 month ago
  1. % Copyright (C) 2001-2023 Artifex Software, Inc.
  2. % All Rights Reserved.
  3. %
  4. % This software is provided AS-IS with no warranty, either express or
  5. % implied.
  6. %
  7. % This software is distributed under license and may not be copied,
  8. % modified or distributed except as expressly authorized under the terms
  9. % of the license contained in the file LICENSE in this distribution.
  10. %
  11. % Refer to licensing information at http://www.artifex.com or contact
  12. % Artifex Software, Inc., 39 Mesa Street, Suite 108A, San Francisco,
  13. % CA 94129, USA, for further information.
  14. %
  15. % Allow the interpreter to encapsulate EPS files, to recognize MS-DOS
  16. % EPSF file headers, and skip to the PostScript section of the file.
  17. % Encapsulate EPS files and optionally resize page or rescale image.
  18. % To display an EPS file cropped to the bounding box:
  19. % gs -dEPSCrop file.eps
  20. % To display an EPS file scaled to fit the page:
  21. % gs -dEPSFitPage file.eps
  22. % To display a file without EPS encapsulation:
  23. % gs -dNOEPS file.ps
  24. % When starting to process an EPS file, state is 0.
  25. % After %%BoundingBox processed, state is 1 if OK or 2 if cropped.
  26. % After %%HiResBoundingBox processed, state is 3 if OK or 4 if cropped.
  27. % After %%EndComments processed, state is 5.
  28. /EPSBoundingBoxState 5 def
  29. /EPSBoundingBoxString () def % set if either BoundingBox is seen (even if invalid)
  30. /EPSBoundingBoxSetState {
  31. //systemdict /EPSBoundingBoxState 3 -1 roll .forceput
  32. } .forcebind odef % .forceput must be bound and hidden
  33. % Parse 4 numbers for a bounding box
  34. /EPSBoundingBoxParse { % (llx lly urx ury) -- llx lly urx ury true OR false
  35. mark exch
  36. token {exch token {exch token {exch token {exch pop} if} if} if} if
  37. counttomark
  38. 4 eq {
  39. 5 -1 roll pop % remove mark
  40. //true
  41. } {
  42. cleartomark //false
  43. } ifelse
  44. } .internalbind odef
  45. % Crop the page to the BoundingBox
  46. /EPSBoundingBoxCrop { % llx lly urx ury --
  47. EPSDEBUG {
  48. (gs_epsf.ps: Setting pagesize from EPS bounding box\n) print flush
  49. } if
  50. exch 3 index sub exch 2 index sub % stack: llx lly urx-llx ury-lly
  51. << /PageSize [ 5 -2 roll ] >> setpagedevice
  52. neg exch neg exch translate
  53. } .internalbind odef
  54. % Rescale, translate and rotate to fit the BoundingBox on the page
  55. /EPSBoundingBoxFitPage { % llx lly urx ury --
  56. EPSDEBUG { (gs_epsf.ps: Rescaling EPS to fit page\n) print flush } if
  57. clippath pathbbox newpath % ellx elly eurx eury pllx plly purx pury
  58. EPSDEBUG {
  59. (Page Coordinates: LLX: ) print 3 index =print (, LLY: ) print
  60. 2 index =print (, URX: ) print 1 index =print (, URY: ) print dup = flush
  61. } if
  62. % Convert box corners to coordinates of the center and box sizes
  63. 2 { % loop doing the page coordinates, the the EPS bbox coordinates
  64. 3 -1 roll exch % ... llx urx lly ury
  65. 2 { % loop doing Y then X coordnates
  66. 2 copy exch sub % ... llx urx lly ury ury-lly
  67. 3 1 roll % ... llx urx ury-lly lly ury
  68. add 2 div % ... llx urx ury-lly (lly+ury)/2
  69. 4 2 roll % ... ury-lly (lly+ury)/2 llx urx
  70. } repeat
  71. 8 4 roll
  72. } repeat
  73. % edx, edy = EPS dimension X and Y, ecx, ecy = EPS Center X and Y.
  74. % pdx and pcx, etc, are for the Page values.
  75. % edx ecx edy ecy pdx pcx pdy pcy
  76. % Move the origin to the center of the printable area.
  77. 3 -1 roll exch % edx ecx edy ecy pdx pdy pcx pcy
  78. translate % edx ecx edy ecy pdx pdy
  79. % Find orientation of the best fit. Square pages or files don't rotate.
  80. 2 copy sub % edx ecx edy ecy pdx pdy pdx-pdy
  81. EPSDEBUG {
  82. (pdx: ) print 2 index =print (, pdy: ) print 1 index =print
  83. (, pdx-pdy: ) print dup = flush
  84. } if
  85. 6 index 5 index sub
  86. EPSDEBUG {
  87. (edx: ) print 7 index =print (, edy: ) print 5 index =print
  88. (, edx-edy: ) print dup = flush
  89. } if
  90. mul % edx ecx edy ecy pdx pdy (pdx-pdy)*(edx-edy)
  91. EPSDEBUG {
  92. (product: ) print dup = flush
  93. } if
  94. 0 lt {
  95. 90 rotate
  96. exch
  97. } if
  98. % Scale to fit in the most restricting direction.
  99. 4 -1 roll div % edx ecx ecy pdx pdy/edy
  100. exch 5 -1 roll div % ecx ecy pdy/edy pdx/edx
  101. //.min exec
  102. dup scale % ecx ecy
  103. % Center the document
  104. neg exch neg exch translate
  105. } .internalbind odef
  106. /EPSBoundingBoxProcess { % (llx lly urx ury) state --
  107. % The following 'lt' check prioritzies HiResBoundingBox over BoundingBox
  108. % even if HiResBoundingBox occurs first in the EPS file.
  109. //systemdict /EPSBoundingBoxState get 1 index lt {
  110. % save the BBoxString for possible FitPage when EndComments is seen
  111. exch dup currentglobal //true setglobal exch
  112. dup length string copy //systemdict /EPSBoundingBoxString 3 -1 roll .forceput
  113. setglobal
  114. EPSBoundingBoxParse
  115. {
  116. //systemdict /EPSCrop known {
  117. EPSBoundingBoxCrop
  118. } {
  119. //systemdict /EPSFitPage known not {
  120. % Warn if some of the EPS file will be clipped
  121. clippath pathbbox newpath
  122. { % context for exit
  123. 5 -1 roll lt { 6 { pop } repeat //true exit } if
  124. 4 -1 roll lt { 4 { pop } repeat //true exit } if
  125. 3 -1 roll gt { 2 { pop } repeat //true exit } if
  126. exch gt { //true exit } if
  127. //false exit
  128. } loop
  129. QUIET not and /EPSBoundingBoxState .systemvar 1 and 1 eq and {
  130. (\n **** Warning: Some of the BoundingBox for the EPS file will be clipped.) =
  131. ( Use -dEPSCrop or -dEPSFitPage to avoid clipping.\n) =
  132. flush
  133. 1 add
  134. } if
  135. } {
  136. pop pop pop pop
  137. } ifelse
  138. } ifelse
  139. EPSBoundingBoxSetState
  140. } {
  141. % improperly formed BoundingBox string.
  142. QUIET not {
  143. (\n **** Warning: BoundingBox values are invalid and will be ignored: ') print
  144. EPSBoundBoxString print (') = flush
  145. } if
  146. pop % state
  147. } ifelse
  148. } {
  149. pop pop
  150. } ifelse
  151. } .internalbind odef
  152. % Perform anchorsearch on the strings in the array until a match is found.
  153. /anchorsearchforany { % haystack [needle1 ...] --> post needle true
  154. % --> haystack false
  155. false 3 1 roll % false haystack [...]
  156. { % false haystack needle
  157. dup 3 1 roll % false needle haystack needle
  158. anchorsearch {
  159. % false needle post needle
  160. pop % false needle post
  161. 3 1 roll % post false needle
  162. exch not exch % post true needle
  163. exit
  164. } {
  165. % false needle haystack
  166. exch pop % false haystack
  167. } ifelse
  168. } forall
  169. exch % haystack false | post needle true
  170. } .internalbind def
  171. /ProcessEPSComment { % file comment -- file comment
  172. /EPSBoundingBoxState .systemvar 3 lt {
  173. dup
  174. (%%BoundingBox:) anchorsearch {
  175. pop
  176. EPSDEBUG { (gs_epsf.ps: found %%BoundingBox\n) print flush } if
  177. 1 EPSBoundingBoxProcess
  178. } {
  179. (%%HiResBoundingBox:) anchorsearch {
  180. pop
  181. EPSDEBUG { (gs_epsf.ps: found %%HiResBoundingBox\n) print flush } if
  182. 3 EPSBoundingBoxProcess
  183. } {
  184. pop % Not interested in this DSC comment
  185. } ifelse
  186. } ifelse
  187. } if
  188. /EPSBoundingBoxState .systemvar 5 lt {
  189. dup (%%DocumentCustomColors:) anchorsearch {
  190. pop
  191. [ exch
  192. { {
  193. token not { exit } if
  194. dup type /stringtype ne { stop } if
  195. dup (atend) eq { stop } if
  196. exch
  197. } loop
  198. {
  199. counttomark 2 add index
  200. dup (123) .peekstring not { stop } if
  201. (%%+) eq {
  202. dup (123) readstring pop pop
  203. 256 string readline pop
  204. cvx exec
  205. } {
  206. pop exit
  207. } ifelse
  208. } loop
  209. } stopped {
  210. cleartomark
  211. } {
  212. counttomark 0 gt {
  213. currentpagedevice /MaxSeparations get 4 gt {
  214. ] << /SeparationColorNames 3 -1 roll >> setpagedevice
  215. } {
  216. cleartomark
  217. } ifelse
  218. } {
  219. cleartomark
  220. } ifelse
  221. } ifelse
  222. } {
  223. {(%%EndComments) (%%BeginProlog) (%%BeginSetup)} anchorsearchforany {
  224. EPSDEBUG { (EPSComment processing finished, encountered: ) print dup = } if
  225. pop pop % discard the strings from the anchorsearch
  226. % We may have seen BoundingBox or HiResBounfingBox. If so and if EPSFitPage
  227. % is set, then we do the transformation here to scale and center the page,
  228. % rotating if needed (and AllowFitPageRotation is true -- the default.)
  229. //systemdict /EPSFitPage known
  230. //systemdict /EPSBoundingBoxState get 0 gt
  231. and {
  232. EPSBoundingBoxString EPSBoundingBoxParse {
  233. EPSBoundingBoxFitPage
  234. } if
  235. } if
  236. % Ignore any following comments
  237. 5 EPSBoundingBoxSetState
  238. } {
  239. pop % Not %%EndComments -- ignore it
  240. } ifelse
  241. } ifelse
  242. } if
  243. } .internalbind def
  244. % Install EPS handler for DSC comments, which we do later
  245. /EPSBoundingBoxInit {
  246. systemdict /NOEPS known not {
  247. % Merge ProcessEPSComment with existing handler
  248. //ProcessEPSComment /exec load
  249. currentuserparams /ProcessDSCComment get
  250. dup //null eq {pop {pop pop}} if /exec load
  251. 4 array astore cvx readonly
  252. << /ProcessDSCComment 3 -1 roll >> setuserparams
  253. } if
  254. } .internalbind odef
  255. /.runNoEPS /run load def
  256. /.runEPS { % file OR string --
  257. .updatematrices
  258. /runEPS_save save def
  259. /runEPS_dict_count countdictstack def
  260. /runEPS_op_count count 2 sub def
  261. /runEPS_page_count .currentshowpagecount not {0} if def
  262. 0 EPSBoundingBoxSetState
  263. //.runNoEPS
  264. .currentshowpagecount not {0} if runEPS_page_count sub 0 eq
  265. { /showpage load exec } if
  266. count runEPS_op_count sub {pop} repeat
  267. countdictstack runEPS_dict_count sub {end} repeat
  268. runEPS_save restore
  269. } .internalbind odef
  270. /run { % file OR string --
  271. dup type /filetype ne { (r) file } if
  272. dup (%!PS-Adobe-) .peekstring {
  273. (%!PS-Adobe-) eq {
  274. dup (%!PS-Adobe-X.X EPSF-X.X) .peekstring {
  275. (EPSF) search {
  276. pop pop pop
  277. EPSDEBUG {(runEPS: Found EPS\n) print flush} if
  278. systemdict /NOEPS known {
  279. cvx //.runNoEPS
  280. } {
  281. cvx .runEPS
  282. } ifelse
  283. } {
  284. EPSDEBUG {(runEPS: Normal DSC\n) print flush} if
  285. pop
  286. cvx //.runNoEPS
  287. } ifelse
  288. } {
  289. EPSDEBUG {(runEPS: Short DSC\n) print flush} if
  290. pop
  291. cvx //.runNoEPS
  292. } ifelse
  293. } {
  294. EPSDEBUG {(runEPS: Not DSC\n) print flush} if
  295. cvx //.runNoEPS
  296. } ifelse
  297. } {
  298. EPSDEBUG {(runEPS: Short non-DSC\n) print flush} if
  299. pop
  300. cvx //.runNoEPS
  301. } ifelse
  302. } .internalbind odef
  303. % Handle DOS EPS files.
  304. /.runnoepsf /run load def
  305. /.epsfheader <C5D0D3C6> def
  306. /run
  307. { dup type /filetype ne { (r) file } if
  308. % Check for MS-DOS EPSF file (see Red Book p. 729).
  309. dup ( ) .peekstring
  310. { .epsfheader eq { dup ( ) readstring exch pop } { //false } ifelse }
  311. { pop //false }
  312. ifelse
  313. % Stack: file true/false
  314. { % This block is executed if the file is MS-DOS EPSF.
  315. % Build up the little-endian byte offset and length.
  316. 2
  317. { 1 0 4
  318. { 2 index read not { pop exit } if % if EOF, let error happen
  319. 2 index mul add exch 256 mul exch
  320. }
  321. repeat exch pop exch
  322. }
  323. repeat
  324. % Stack: offset length file
  325. % Use flushfile to skip quickly to the start of the
  326. % PostScript section.
  327. dup 4 -1 roll 12 sub () /SubFileDecode filter flushfile
  328. % Now interpret the PostScript.
  329. exch () /SubFileDecode filter cvx run
  330. }
  331. { //.runnoepsf
  332. }
  333. ifelse
  334. } odef
  335. % rebind .runstdin to use redefined run
  336. userdict begin
  337. /.runstdin {
  338. { (%stdin) run } execute0
  339. } .internalbind def
  340. end
  341. % undefine things defined in this file and not referenced elsewhere
  342. [
  343. /.runNoEPS
  344. /.runnoepsf
  345. /.runEPS
  346. /EPSBoundingBoxSetState
  347. /EPSBoundingBoxString
  348. /EPSBoundingBoxCrop
  349. /EPSBoundingBoxFitPage
  350. /EPSBoundingBoxParse
  351. /EPSBoundingBoxProcess
  352. /ProcessEPSComment
  353. ] currentdict .undefinternalnames