pdf2json 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (473) hide show
  1. data/README.markdown +9 -0
  2. data/bin/.gitkeep +0 -0
  3. data/ext/extconf.rb +30 -0
  4. data/lib/pdf2json.rb +8 -0
  5. data/pdf2json-0.52-source/AUTHORS +24 -0
  6. data/pdf2json-0.52-source/CHANGES +11 -0
  7. data/pdf2json-0.52-source/Makefile +84 -0
  8. data/pdf2json-0.52-source/Makefile.in +84 -0
  9. data/pdf2json-0.52-source/aclocal.m4 +274 -0
  10. data/pdf2json-0.52-source/aconf-win32.h +86 -0
  11. data/pdf2json-0.52-source/aconf.h +42 -0
  12. data/pdf2json-0.52-source/aconf.h.in +41 -0
  13. data/pdf2json-0.52-source/autom4te.cache/output.0 +6908 -0
  14. data/pdf2json-0.52-source/autom4te.cache/requests +76 -0
  15. data/pdf2json-0.52-source/autom4te.cache/traces.0 +466 -0
  16. data/pdf2json-0.52-source/config.log +1259 -0
  17. data/pdf2json-0.52-source/config.status +1050 -0
  18. data/pdf2json-0.52-source/configure +6908 -0
  19. data/pdf2json-0.52-source/configure.ac +93 -0
  20. data/pdf2json-0.52-source/doc/pdffonts.1 +130 -0
  21. data/pdf2json-0.52-source/doc/pdffonts.cat +107 -0
  22. data/pdf2json-0.52-source/doc/pdffonts.hlp +117 -0
  23. data/pdf2json-0.52-source/doc/pdfimages.1 +102 -0
  24. data/pdf2json-0.52-source/doc/pdfimages.cat +92 -0
  25. data/pdf2json-0.52-source/doc/pdfimages.hlp +101 -0
  26. data/pdf2json-0.52-source/doc/pdfinfo.1 +158 -0
  27. data/pdf2json-0.52-source/doc/pdfinfo.cat +119 -0
  28. data/pdf2json-0.52-source/doc/pdfinfo.hlp +129 -0
  29. data/pdf2json-0.52-source/doc/pdftoppm.1 +115 -0
  30. data/pdf2json-0.52-source/doc/pdftoppm.cat +105 -0
  31. data/pdf2json-0.52-source/doc/pdftoppm.hlp +114 -0
  32. data/pdf2json-0.52-source/doc/pdftops.1 +229 -0
  33. data/pdf2json-0.52-source/doc/pdftops.cat +221 -0
  34. data/pdf2json-0.52-source/doc/pdftops.hlp +231 -0
  35. data/pdf2json-0.52-source/doc/pdftotext.1 +137 -0
  36. data/pdf2json-0.52-source/doc/pdftotext.cat +120 -0
  37. data/pdf2json-0.52-source/doc/pdftotext.hlp +133 -0
  38. data/pdf2json-0.52-source/doc/sample-xpdfrc +91 -0
  39. data/pdf2json-0.52-source/doc/xpdf.1 +513 -0
  40. data/pdf2json-0.52-source/doc/xpdf.cat +476 -0
  41. data/pdf2json-0.52-source/doc/xpdf.hlp +489 -0
  42. data/pdf2json-0.52-source/doc/xpdfrc.5 +480 -0
  43. data/pdf2json-0.52-source/doc/xpdfrc.cat +474 -0
  44. data/pdf2json-0.52-source/doc/xpdfrc.hlp +479 -0
  45. data/pdf2json-0.52-source/fofi/.DS_Store +0 -0
  46. data/pdf2json-0.52-source/fofi/FoFiBase.cc +156 -0
  47. data/pdf2json-0.52-source/fofi/FoFiBase.h +57 -0
  48. data/pdf2json-0.52-source/fofi/FoFiBase.o +0 -0
  49. data/pdf2json-0.52-source/fofi/FoFiEncodings.cc +994 -0
  50. data/pdf2json-0.52-source/fofi/FoFiEncodings.h +36 -0
  51. data/pdf2json-0.52-source/fofi/FoFiEncodings.o +0 -0
  52. data/pdf2json-0.52-source/fofi/FoFiTrueType.cc +2027 -0
  53. data/pdf2json-0.52-source/fofi/FoFiTrueType.h +174 -0
  54. data/pdf2json-0.52-source/fofi/FoFiTrueType.o +0 -0
  55. data/pdf2json-0.52-source/fofi/FoFiType1.cc +252 -0
  56. data/pdf2json-0.52-source/fofi/FoFiType1.h +59 -0
  57. data/pdf2json-0.52-source/fofi/FoFiType1.o +0 -0
  58. data/pdf2json-0.52-source/fofi/FoFiType1C.cc +2603 -0
  59. data/pdf2json-0.52-source/fofi/FoFiType1C.h +233 -0
  60. data/pdf2json-0.52-source/fofi/FoFiType1C.o +0 -0
  61. data/pdf2json-0.52-source/fofi/Makefile +70 -0
  62. data/pdf2json-0.52-source/fofi/Makefile.dep +0 -0
  63. data/pdf2json-0.52-source/fofi/Makefile.in +70 -0
  64. data/pdf2json-0.52-source/fofi/libfofi.a +0 -0
  65. data/pdf2json-0.52-source/fofi/vms_make.com +0 -0
  66. data/pdf2json-0.52-source/freetype.win32/.DS_Store +0 -0
  67. data/pdf2json-0.52-source/freetype.win32/include/.DS_Store +0 -0
  68. data/pdf2json-0.52-source/freetype.win32/include/freetype/config/ftconfig.h +528 -0
  69. data/pdf2json-0.52-source/freetype.win32/include/freetype/config/ftheader.h +780 -0
  70. data/pdf2json-0.52-source/freetype.win32/include/freetype/config/ftmodule.h +32 -0
  71. data/pdf2json-0.52-source/freetype.win32/include/freetype/config/ftoption.h +733 -0
  72. data/pdf2json-0.52-source/freetype.win32/include/freetype/config/ftstdlib.h +173 -0
  73. data/pdf2json-0.52-source/freetype.win32/include/freetype/freetype.h +3919 -0
  74. data/pdf2json-0.52-source/freetype.win32/include/freetype/ftadvanc.h +179 -0
  75. data/pdf2json-0.52-source/freetype.win32/include/freetype/ftbbox.h +94 -0
  76. data/pdf2json-0.52-source/freetype.win32/include/freetype/ftbdf.h +209 -0
  77. data/pdf2json-0.52-source/freetype.win32/include/freetype/ftbitmap.h +227 -0
  78. data/pdf2json-0.52-source/freetype.win32/include/freetype/ftcache.h +1128 -0
  79. data/pdf2json-0.52-source/freetype.win32/include/freetype/ftchapters.h +103 -0
  80. data/pdf2json-0.52-source/freetype.win32/include/freetype/ftcid.h +166 -0
  81. data/pdf2json-0.52-source/freetype.win32/include/freetype/fterrdef.h +244 -0
  82. data/pdf2json-0.52-source/freetype.win32/include/freetype/fterrors.h +206 -0
  83. data/pdf2json-0.52-source/freetype.win32/include/freetype/ftgasp.h +120 -0
  84. data/pdf2json-0.52-source/freetype.win32/include/freetype/ftglyph.h +613 -0
  85. data/pdf2json-0.52-source/freetype.win32/include/freetype/ftgxval.h +358 -0
  86. data/pdf2json-0.52-source/freetype.win32/include/freetype/ftgzip.h +102 -0
  87. data/pdf2json-0.52-source/freetype.win32/include/freetype/ftimage.h +1313 -0
  88. data/pdf2json-0.52-source/freetype.win32/include/freetype/ftincrem.h +353 -0
  89. data/pdf2json-0.52-source/freetype.win32/include/freetype/ftlcdfil.h +213 -0
  90. data/pdf2json-0.52-source/freetype.win32/include/freetype/ftlist.h +277 -0
  91. data/pdf2json-0.52-source/freetype.win32/include/freetype/ftlzw.h +99 -0
  92. data/pdf2json-0.52-source/freetype.win32/include/freetype/ftmac.h +274 -0
  93. data/pdf2json-0.52-source/freetype.win32/include/freetype/ftmm.h +378 -0
  94. data/pdf2json-0.52-source/freetype.win32/include/freetype/ftmodapi.h +483 -0
  95. data/pdf2json-0.52-source/freetype.win32/include/freetype/ftmoderr.h +155 -0
  96. data/pdf2json-0.52-source/freetype.win32/include/freetype/ftotval.h +203 -0
  97. data/pdf2json-0.52-source/freetype.win32/include/freetype/ftoutln.h +537 -0
  98. data/pdf2json-0.52-source/freetype.win32/include/freetype/ftpfr.h +172 -0
  99. data/pdf2json-0.52-source/freetype.win32/include/freetype/ftrender.h +230 -0
  100. data/pdf2json-0.52-source/freetype.win32/include/freetype/ftsizes.h +159 -0
  101. data/pdf2json-0.52-source/freetype.win32/include/freetype/ftsnames.h +200 -0
  102. data/pdf2json-0.52-source/freetype.win32/include/freetype/ftstroke.h +716 -0
  103. data/pdf2json-0.52-source/freetype.win32/include/freetype/ftsynth.h +80 -0
  104. data/pdf2json-0.52-source/freetype.win32/include/freetype/ftsystem.h +347 -0
  105. data/pdf2json-0.52-source/freetype.win32/include/freetype/fttrigon.h +350 -0
  106. data/pdf2json-0.52-source/freetype.win32/include/freetype/fttypes.h +588 -0
  107. data/pdf2json-0.52-source/freetype.win32/include/freetype/ftwinfnt.h +274 -0
  108. data/pdf2json-0.52-source/freetype.win32/include/freetype/ftxf86.h +83 -0
  109. data/pdf2json-0.52-source/freetype.win32/include/freetype/internal/autohint.h +231 -0
  110. data/pdf2json-0.52-source/freetype.win32/include/freetype/internal/ftcalc.h +179 -0
  111. data/pdf2json-0.52-source/freetype.win32/include/freetype/internal/ftdebug.h +250 -0
  112. data/pdf2json-0.52-source/freetype.win32/include/freetype/internal/ftdriver.h +422 -0
  113. data/pdf2json-0.52-source/freetype.win32/include/freetype/internal/ftgloadr.h +168 -0
  114. data/pdf2json-0.52-source/freetype.win32/include/freetype/internal/ftmemory.h +380 -0
  115. data/pdf2json-0.52-source/freetype.win32/include/freetype/internal/ftobjs.h +1428 -0
  116. data/pdf2json-0.52-source/freetype.win32/include/freetype/internal/ftpic.h +67 -0
  117. data/pdf2json-0.52-source/freetype.win32/include/freetype/internal/ftrfork.h +196 -0
  118. data/pdf2json-0.52-source/freetype.win32/include/freetype/internal/ftserv.h +620 -0
  119. data/pdf2json-0.52-source/freetype.win32/include/freetype/internal/ftstream.h +539 -0
  120. data/pdf2json-0.52-source/freetype.win32/include/freetype/internal/fttrace.h +139 -0
  121. data/pdf2json-0.52-source/freetype.win32/include/freetype/internal/ftvalid.h +150 -0
  122. data/pdf2json-0.52-source/freetype.win32/include/freetype/internal/internal.h +51 -0
  123. data/pdf2json-0.52-source/freetype.win32/include/freetype/internal/pcftypes.h +56 -0
  124. data/pdf2json-0.52-source/freetype.win32/include/freetype/internal/psaux.h +873 -0
  125. data/pdf2json-0.52-source/freetype.win32/include/freetype/internal/pshints.h +712 -0
  126. data/pdf2json-0.52-source/freetype.win32/include/freetype/internal/services/svbdf.h +77 -0
  127. data/pdf2json-0.52-source/freetype.win32/include/freetype/internal/services/svcid.h +83 -0
  128. data/pdf2json-0.52-source/freetype.win32/include/freetype/internal/services/svgldict.h +82 -0
  129. data/pdf2json-0.52-source/freetype.win32/include/freetype/internal/services/svgxval.h +72 -0
  130. data/pdf2json-0.52-source/freetype.win32/include/freetype/internal/services/svkern.h +51 -0
  131. data/pdf2json-0.52-source/freetype.win32/include/freetype/internal/services/svmm.h +104 -0
  132. data/pdf2json-0.52-source/freetype.win32/include/freetype/internal/services/svotval.h +55 -0
  133. data/pdf2json-0.52-source/freetype.win32/include/freetype/internal/services/svpfr.h +66 -0
  134. data/pdf2json-0.52-source/freetype.win32/include/freetype/internal/services/svpostnm.h +79 -0
  135. data/pdf2json-0.52-source/freetype.win32/include/freetype/internal/services/svpscmap.h +164 -0
  136. data/pdf2json-0.52-source/freetype.win32/include/freetype/internal/services/svpsinfo.h +92 -0
  137. data/pdf2json-0.52-source/freetype.win32/include/freetype/internal/services/svsfnt.h +102 -0
  138. data/pdf2json-0.52-source/freetype.win32/include/freetype/internal/services/svttcmap.h +106 -0
  139. data/pdf2json-0.52-source/freetype.win32/include/freetype/internal/services/svtteng.h +53 -0
  140. data/pdf2json-0.52-source/freetype.win32/include/freetype/internal/services/svttglyf.h +67 -0
  141. data/pdf2json-0.52-source/freetype.win32/include/freetype/internal/services/svwinfnt.h +50 -0
  142. data/pdf2json-0.52-source/freetype.win32/include/freetype/internal/services/svxf86nm.h +55 -0
  143. data/pdf2json-0.52-source/freetype.win32/include/freetype/internal/sfnt.h +897 -0
  144. data/pdf2json-0.52-source/freetype.win32/include/freetype/internal/t1types.h +270 -0
  145. data/pdf2json-0.52-source/freetype.win32/include/freetype/internal/tttypes.h +1543 -0
  146. data/pdf2json-0.52-source/freetype.win32/include/freetype/t1tables.h +504 -0
  147. data/pdf2json-0.52-source/freetype.win32/include/freetype/ttnameid.h +1247 -0
  148. data/pdf2json-0.52-source/freetype.win32/include/freetype/tttables.h +759 -0
  149. data/pdf2json-0.52-source/freetype.win32/include/freetype/tttags.h +107 -0
  150. data/pdf2json-0.52-source/freetype.win32/include/freetype/ttunpat.h +59 -0
  151. data/pdf2json-0.52-source/freetype.win32/include/ft2build.h +39 -0
  152. data/pdf2json-0.52-source/freetype.win32/lib/freetype_a.lib +0 -0
  153. data/pdf2json-0.52-source/goo/.DS_Store +0 -0
  154. data/pdf2json-0.52-source/goo/FixedPoint.cc +118 -0
  155. data/pdf2json-0.52-source/goo/FixedPoint.h +155 -0
  156. data/pdf2json-0.52-source/goo/FixedPoint.o +0 -0
  157. data/pdf2json-0.52-source/goo/GHash.cc +380 -0
  158. data/pdf2json-0.52-source/goo/GHash.h +78 -0
  159. data/pdf2json-0.52-source/goo/GHash.o +0 -0
  160. data/pdf2json-0.52-source/goo/GList.cc +97 -0
  161. data/pdf2json-0.52-source/goo/GList.h +96 -0
  162. data/pdf2json-0.52-source/goo/GList.o +0 -0
  163. data/pdf2json-0.52-source/goo/GMutex.h +49 -0
  164. data/pdf2json-0.52-source/goo/GString.cc +724 -0
  165. data/pdf2json-0.52-source/goo/GString.cc.fixed +718 -0
  166. data/pdf2json-0.52-source/goo/GString.h +136 -0
  167. data/pdf2json-0.52-source/goo/GString.o +0 -0
  168. data/pdf2json-0.52-source/goo/ImgWriter.o +0 -0
  169. data/pdf2json-0.52-source/goo/JpegWriter.o +0 -0
  170. data/pdf2json-0.52-source/goo/Makefile +72 -0
  171. data/pdf2json-0.52-source/goo/Makefile.dep +0 -0
  172. data/pdf2json-0.52-source/goo/Makefile.in +72 -0
  173. data/pdf2json-0.52-source/goo/PNGWriter.o +0 -0
  174. data/pdf2json-0.52-source/goo/gfile.cc +731 -0
  175. data/pdf2json-0.52-source/goo/gfile.h +138 -0
  176. data/pdf2json-0.52-source/goo/gfile.o +0 -0
  177. data/pdf2json-0.52-source/goo/gmem.cc +264 -0
  178. data/pdf2json-0.52-source/goo/gmem.h +79 -0
  179. data/pdf2json-0.52-source/goo/gmem.o +0 -0
  180. data/pdf2json-0.52-source/goo/gmempp.cc +32 -0
  181. data/pdf2json-0.52-source/goo/gmempp.o +0 -0
  182. data/pdf2json-0.52-source/goo/gtypes.h +29 -0
  183. data/pdf2json-0.52-source/goo/libGoo.a +0 -0
  184. data/pdf2json-0.52-source/goo/parseargs.c +190 -0
  185. data/pdf2json-0.52-source/goo/parseargs.h +71 -0
  186. data/pdf2json-0.52-source/goo/parseargs.o +0 -0
  187. data/pdf2json-0.52-source/goo/vms_directory.c +214 -0
  188. data/pdf2json-0.52-source/goo/vms_dirent.h +67 -0
  189. data/pdf2json-0.52-source/goo/vms_make.com +82 -0
  190. data/pdf2json-0.52-source/goo/vms_sys_dirent.h +54 -0
  191. data/pdf2json-0.52-source/goo/vms_unix_time.h +102 -0
  192. data/pdf2json-0.52-source/goo/vms_unix_times.c +42 -0
  193. data/pdf2json-0.52-source/goo/vms_unlink.c +22 -0
  194. data/pdf2json-0.52-source/ms_make.bat +199 -0
  195. data/pdf2json-0.52-source/splash/.DS_Store +0 -0
  196. data/pdf2json-0.52-source/splash/Makefile +103 -0
  197. data/pdf2json-0.52-source/splash/Makefile.dep +0 -0
  198. data/pdf2json-0.52-source/splash/Makefile.in +103 -0
  199. data/pdf2json-0.52-source/splash/Splash.cc +3310 -0
  200. data/pdf2json-0.52-source/splash/Splash.h +293 -0
  201. data/pdf2json-0.52-source/splash/Splash.o +0 -0
  202. data/pdf2json-0.52-source/splash/SplashBitmap.cc +188 -0
  203. data/pdf2json-0.52-source/splash/SplashBitmap.h +64 -0
  204. data/pdf2json-0.52-source/splash/SplashBitmap.o +0 -0
  205. data/pdf2json-0.52-source/splash/SplashClip.cc +382 -0
  206. data/pdf2json-0.52-source/splash/SplashClip.h +107 -0
  207. data/pdf2json-0.52-source/splash/SplashClip.o +0 -0
  208. data/pdf2json-0.52-source/splash/SplashErrorCodes.h +32 -0
  209. data/pdf2json-0.52-source/splash/SplashFTFont.cc +357 -0
  210. data/pdf2json-0.52-source/splash/SplashFTFont.h +58 -0
  211. data/pdf2json-0.52-source/splash/SplashFTFont.o +0 -0
  212. data/pdf2json-0.52-source/splash/SplashFTFontEngine.cc +179 -0
  213. data/pdf2json-0.52-source/splash/SplashFTFontEngine.h +65 -0
  214. data/pdf2json-0.52-source/splash/SplashFTFontEngine.o +0 -0
  215. data/pdf2json-0.52-source/splash/SplashFTFontFile.cc +114 -0
  216. data/pdf2json-0.52-source/splash/SplashFTFontFile.h +73 -0
  217. data/pdf2json-0.52-source/splash/SplashFTFontFile.o +0 -0
  218. data/pdf2json-0.52-source/splash/SplashFont.cc +176 -0
  219. data/pdf2json-0.52-source/splash/SplashFont.h +104 -0
  220. data/pdf2json-0.52-source/splash/SplashFont.o +0 -0
  221. data/pdf2json-0.52-source/splash/SplashFontEngine.cc +317 -0
  222. data/pdf2json-0.52-source/splash/SplashFontEngine.h +91 -0
  223. data/pdf2json-0.52-source/splash/SplashFontEngine.o +0 -0
  224. data/pdf2json-0.52-source/splash/SplashFontFile.cc +55 -0
  225. data/pdf2json-0.52-source/splash/SplashFontFile.h +60 -0
  226. data/pdf2json-0.52-source/splash/SplashFontFile.o +0 -0
  227. data/pdf2json-0.52-source/splash/SplashFontFileID.cc +23 -0
  228. data/pdf2json-0.52-source/splash/SplashFontFileID.h +30 -0
  229. data/pdf2json-0.52-source/splash/SplashFontFileID.o +0 -0
  230. data/pdf2json-0.52-source/splash/SplashGlyphBitmap.h +26 -0
  231. data/pdf2json-0.52-source/splash/SplashMath.h +89 -0
  232. data/pdf2json-0.52-source/splash/SplashPath.cc +184 -0
  233. data/pdf2json-0.52-source/splash/SplashPath.h +121 -0
  234. data/pdf2json-0.52-source/splash/SplashPath.o +0 -0
  235. data/pdf2json-0.52-source/splash/SplashPattern.cc +40 -0
  236. data/pdf2json-0.52-source/splash/SplashPattern.h +65 -0
  237. data/pdf2json-0.52-source/splash/SplashPattern.o +0 -0
  238. data/pdf2json-0.52-source/splash/SplashScreen.cc +383 -0
  239. data/pdf2json-0.52-source/splash/SplashScreen.h +56 -0
  240. data/pdf2json-0.52-source/splash/SplashScreen.o +0 -0
  241. data/pdf2json-0.52-source/splash/SplashState.cc +165 -0
  242. data/pdf2json-0.52-source/splash/SplashState.h +103 -0
  243. data/pdf2json-0.52-source/splash/SplashState.o +0 -0
  244. data/pdf2json-0.52-source/splash/SplashT1Font.cc +287 -0
  245. data/pdf2json-0.52-source/splash/SplashT1Font.h +57 -0
  246. data/pdf2json-0.52-source/splash/SplashT1Font.o +0 -0
  247. data/pdf2json-0.52-source/splash/SplashT1FontEngine.cc +124 -0
  248. data/pdf2json-0.52-source/splash/SplashT1FontEngine.h +53 -0
  249. data/pdf2json-0.52-source/splash/SplashT1FontEngine.o +0 -0
  250. data/pdf2json-0.52-source/splash/SplashT1FontFile.cc +97 -0
  251. data/pdf2json-0.52-source/splash/SplashT1FontFile.h +58 -0
  252. data/pdf2json-0.52-source/splash/SplashT1FontFile.o +0 -0
  253. data/pdf2json-0.52-source/splash/SplashTypes.h +132 -0
  254. data/pdf2json-0.52-source/splash/SplashXPath.cc +438 -0
  255. data/pdf2json-0.52-source/splash/SplashXPath.h +100 -0
  256. data/pdf2json-0.52-source/splash/SplashXPath.o +0 -0
  257. data/pdf2json-0.52-source/splash/SplashXPathScanner.cc +428 -0
  258. data/pdf2json-0.52-source/splash/SplashXPathScanner.h +87 -0
  259. data/pdf2json-0.52-source/splash/SplashXPathScanner.o +0 -0
  260. data/pdf2json-0.52-source/splash/libsplash.a +0 -0
  261. data/pdf2json-0.52-source/splash/vms_make.com +0 -0
  262. data/pdf2json-0.52-source/src/.DS_Store +0 -0
  263. data/pdf2json-0.52-source/src/GVector.h +101 -0
  264. data/pdf2json-0.52-source/src/ImgOutputDev.cc +1243 -0
  265. data/pdf2json-0.52-source/src/ImgOutputDev.h +307 -0
  266. data/pdf2json-0.52-source/src/ImgOutputDev.o +0 -0
  267. data/pdf2json-0.52-source/src/Makefile +68 -0
  268. data/pdf2json-0.52-source/src/Makefile.in +68 -0
  269. data/pdf2json-0.52-source/src/XmlFonts.cc +367 -0
  270. data/pdf2json-0.52-source/src/XmlFonts.h +91 -0
  271. data/pdf2json-0.52-source/src/XmlFonts.o +0 -0
  272. data/pdf2json-0.52-source/src/XmlLinks.cc +101 -0
  273. data/pdf2json-0.52-source/src/XmlLinks.h +54 -0
  274. data/pdf2json-0.52-source/src/XmlLinks.o +0 -0
  275. data/pdf2json-0.52-source/src/pdf2json +0 -0
  276. data/pdf2json-0.52-source/src/pdf2json.cc +343 -0
  277. data/pdf2json-0.52-source/src/pdf2json.o +0 -0
  278. data/pdf2json-0.52-source/src/pdf2xml.dtd +22 -0
  279. data/pdf2json-0.52-source/src/pdf2xmljson.dtd +9 -0
  280. data/pdf2json-0.52-source/xpdf/.DS_Store +0 -0
  281. data/pdf2json-0.52-source/xpdf/Annot.cc +1556 -0
  282. data/pdf2json-0.52-source/xpdf/Annot.h +142 -0
  283. data/pdf2json-0.52-source/xpdf/Annot.o +0 -0
  284. data/pdf2json-0.52-source/xpdf/Array.cc +73 -0
  285. data/pdf2json-0.52-source/xpdf/Array.h +58 -0
  286. data/pdf2json-0.52-source/xpdf/Array.o +0 -0
  287. data/pdf2json-0.52-source/xpdf/BuiltinFont.cc +65 -0
  288. data/pdf2json-0.52-source/xpdf/BuiltinFont.h +57 -0
  289. data/pdf2json-0.52-source/xpdf/BuiltinFont.o +0 -0
  290. data/pdf2json-0.52-source/xpdf/BuiltinFontTables.cc +4284 -0
  291. data/pdf2json-0.52-source/xpdf/BuiltinFontTables.h +23 -0
  292. data/pdf2json-0.52-source/xpdf/BuiltinFontTables.o +0 -0
  293. data/pdf2json-0.52-source/xpdf/CMap.cc +408 -0
  294. data/pdf2json-0.52-source/xpdf/CMap.h +102 -0
  295. data/pdf2json-0.52-source/xpdf/CMap.o +0 -0
  296. data/pdf2json-0.52-source/xpdf/Catalog.cc +374 -0
  297. data/pdf2json-0.52-source/xpdf/Catalog.h +97 -0
  298. data/pdf2json-0.52-source/xpdf/Catalog.o +0 -0
  299. data/pdf2json-0.52-source/xpdf/CharCodeToUnicode.cc +540 -0
  300. data/pdf2json-0.52-source/xpdf/CharCodeToUnicode.h +117 -0
  301. data/pdf2json-0.52-source/xpdf/CharCodeToUnicode.o +0 -0
  302. data/pdf2json-0.52-source/xpdf/CharTypes.h +24 -0
  303. data/pdf2json-0.52-source/xpdf/CompactFontTables.h +464 -0
  304. data/pdf2json-0.52-source/xpdf/CoreOutputDev.cc +61 -0
  305. data/pdf2json-0.52-source/xpdf/CoreOutputDev.h +61 -0
  306. data/pdf2json-0.52-source/xpdf/Decrypt.cc +776 -0
  307. data/pdf2json-0.52-source/xpdf/Decrypt.h +95 -0
  308. data/pdf2json-0.52-source/xpdf/Decrypt.o +0 -0
  309. data/pdf2json-0.52-source/xpdf/Dict.cc +95 -0
  310. data/pdf2json-0.52-source/xpdf/Dict.h +77 -0
  311. data/pdf2json-0.52-source/xpdf/Dict.o +0 -0
  312. data/pdf2json-0.52-source/xpdf/Error.cc +38 -0
  313. data/pdf2json-0.52-source/xpdf/Error.h +23 -0
  314. data/pdf2json-0.52-source/xpdf/Error.o +0 -0
  315. data/pdf2json-0.52-source/xpdf/ErrorCodes.h +36 -0
  316. data/pdf2json-0.52-source/xpdf/FontEncodingTables.cc +1824 -0
  317. data/pdf2json-0.52-source/xpdf/FontEncodingTables.h +20 -0
  318. data/pdf2json-0.52-source/xpdf/FontEncodingTables.o +0 -0
  319. data/pdf2json-0.52-source/xpdf/Function.cc +1573 -0
  320. data/pdf2json-0.52-source/xpdf/Function.h +229 -0
  321. data/pdf2json-0.52-source/xpdf/Function.o +0 -0
  322. data/pdf2json-0.52-source/xpdf/Gfx.cc +4187 -0
  323. data/pdf2json-0.52-source/xpdf/Gfx.h +312 -0
  324. data/pdf2json-0.52-source/xpdf/Gfx.o +0 -0
  325. data/pdf2json-0.52-source/xpdf/GfxFont.cc +1568 -0
  326. data/pdf2json-0.52-source/xpdf/GfxFont.h +320 -0
  327. data/pdf2json-0.52-source/xpdf/GfxFont.o +0 -0
  328. data/pdf2json-0.52-source/xpdf/GfxState.cc +4137 -0
  329. data/pdf2json-0.52-source/xpdf/GfxState.h +1244 -0
  330. data/pdf2json-0.52-source/xpdf/GfxState.o +0 -0
  331. data/pdf2json-0.52-source/xpdf/GlobalParams.cc +2924 -0
  332. data/pdf2json-0.52-source/xpdf/GlobalParams.cc.old +2908 -0
  333. data/pdf2json-0.52-source/xpdf/GlobalParams.h +466 -0
  334. data/pdf2json-0.52-source/xpdf/GlobalParams.h.old +463 -0
  335. data/pdf2json-0.52-source/xpdf/GlobalParams.o +0 -0
  336. data/pdf2json-0.52-source/xpdf/ImageOutputDev.cc +195 -0
  337. data/pdf2json-0.52-source/xpdf/ImageOutputDev.h +76 -0
  338. data/pdf2json-0.52-source/xpdf/ImageOutputDev.o +0 -0
  339. data/pdf2json-0.52-source/xpdf/JArithmeticDecoder.cc +322 -0
  340. data/pdf2json-0.52-source/xpdf/JArithmeticDecoder.h +109 -0
  341. data/pdf2json-0.52-source/xpdf/JArithmeticDecoder.o +0 -0
  342. data/pdf2json-0.52-source/xpdf/JBIG2Stream.cc +3413 -0
  343. data/pdf2json-0.52-source/xpdf/JBIG2Stream.h +145 -0
  344. data/pdf2json-0.52-source/xpdf/JBIG2Stream.o +0 -0
  345. data/pdf2json-0.52-source/xpdf/JPXStream.cc +3144 -0
  346. data/pdf2json-0.52-source/xpdf/JPXStream.h +351 -0
  347. data/pdf2json-0.52-source/xpdf/JPXStream.o +0 -0
  348. data/pdf2json-0.52-source/xpdf/Lexer.cc +485 -0
  349. data/pdf2json-0.52-source/xpdf/Lexer.h +80 -0
  350. data/pdf2json-0.52-source/xpdf/Lexer.o +0 -0
  351. data/pdf2json-0.52-source/xpdf/Link.cc +806 -0
  352. data/pdf2json-0.52-source/xpdf/Link.cc.old +784 -0
  353. data/pdf2json-0.52-source/xpdf/Link.h +415 -0
  354. data/pdf2json-0.52-source/xpdf/Link.h.old +369 -0
  355. data/pdf2json-0.52-source/xpdf/Link.o +0 -0
  356. data/pdf2json-0.52-source/xpdf/Makefile +232 -0
  357. data/pdf2json-0.52-source/xpdf/Makefile.dep +0 -0
  358. data/pdf2json-0.52-source/xpdf/Makefile.in +232 -0
  359. data/pdf2json-0.52-source/xpdf/NameToCharCode.cc +116 -0
  360. data/pdf2json-0.52-source/xpdf/NameToCharCode.h +42 -0
  361. data/pdf2json-0.52-source/xpdf/NameToCharCode.o +0 -0
  362. data/pdf2json-0.52-source/xpdf/NameToUnicodeTable.h +1097 -0
  363. data/pdf2json-0.52-source/xpdf/Object.cc +231 -0
  364. data/pdf2json-0.52-source/xpdf/Object.h +303 -0
  365. data/pdf2json-0.52-source/xpdf/Object.o +0 -0
  366. data/pdf2json-0.52-source/xpdf/Outline.cc +151 -0
  367. data/pdf2json-0.52-source/xpdf/Outline.h +76 -0
  368. data/pdf2json-0.52-source/xpdf/Outline.o +0 -0
  369. data/pdf2json-0.52-source/xpdf/OutputDev.cc +131 -0
  370. data/pdf2json-0.52-source/xpdf/OutputDev.h +253 -0
  371. data/pdf2json-0.52-source/xpdf/OutputDev.o +0 -0
  372. data/pdf2json-0.52-source/xpdf/PDFCore.cc +2044 -0
  373. data/pdf2json-0.52-source/xpdf/PDFCore.h +321 -0
  374. data/pdf2json-0.52-source/xpdf/PDFDoc.cc +404 -0
  375. data/pdf2json-0.52-source/xpdf/PDFDoc.h +183 -0
  376. data/pdf2json-0.52-source/xpdf/PDFDoc.o +0 -0
  377. data/pdf2json-0.52-source/xpdf/PDFDocEncoding.cc +44 -0
  378. data/pdf2json-0.52-source/xpdf/PDFDocEncoding.h +16 -0
  379. data/pdf2json-0.52-source/xpdf/PDFDocEncoding.o +0 -0
  380. data/pdf2json-0.52-source/xpdf/PSOutputDev.cc +6224 -0
  381. data/pdf2json-0.52-source/xpdf/PSOutputDev.h +395 -0
  382. data/pdf2json-0.52-source/xpdf/PSOutputDev.o +0 -0
  383. data/pdf2json-0.52-source/xpdf/PSTokenizer.cc +135 -0
  384. data/pdf2json-0.52-source/xpdf/PSTokenizer.h +41 -0
  385. data/pdf2json-0.52-source/xpdf/PSTokenizer.o +0 -0
  386. data/pdf2json-0.52-source/xpdf/Page.cc +454 -0
  387. data/pdf2json-0.52-source/xpdf/Page.h +187 -0
  388. data/pdf2json-0.52-source/xpdf/Page.o +0 -0
  389. data/pdf2json-0.52-source/xpdf/Parser.cc +227 -0
  390. data/pdf2json-0.52-source/xpdf/Parser.h +59 -0
  391. data/pdf2json-0.52-source/xpdf/Parser.o +0 -0
  392. data/pdf2json-0.52-source/xpdf/PreScanOutputDev.cc +257 -0
  393. data/pdf2json-0.52-source/xpdf/PreScanOutputDev.h +130 -0
  394. data/pdf2json-0.52-source/xpdf/PreScanOutputDev.o +0 -0
  395. data/pdf2json-0.52-source/xpdf/SecurityHandler.cc +390 -0
  396. data/pdf2json-0.52-source/xpdf/SecurityHandler.h +160 -0
  397. data/pdf2json-0.52-source/xpdf/SecurityHandler.o +0 -0
  398. data/pdf2json-0.52-source/xpdf/SplashOutputDev.cc +2845 -0
  399. data/pdf2json-0.52-source/xpdf/SplashOutputDev.h +247 -0
  400. data/pdf2json-0.52-source/xpdf/SplashOutputDev.o +0 -0
  401. data/pdf2json-0.52-source/xpdf/Stream-CCITT.h +459 -0
  402. data/pdf2json-0.52-source/xpdf/Stream.cc +4627 -0
  403. data/pdf2json-0.52-source/xpdf/Stream.h +858 -0
  404. data/pdf2json-0.52-source/xpdf/Stream.o +0 -0
  405. data/pdf2json-0.52-source/xpdf/TextOutputDev.cc +4090 -0
  406. data/pdf2json-0.52-source/xpdf/TextOutputDev.h +661 -0
  407. data/pdf2json-0.52-source/xpdf/TextOutputDev.o +0 -0
  408. data/pdf2json-0.52-source/xpdf/UTF8.h +56 -0
  409. data/pdf2json-0.52-source/xpdf/UnicodeMap.cc +302 -0
  410. data/pdf2json-0.52-source/xpdf/UnicodeMap.cc.old +293 -0
  411. data/pdf2json-0.52-source/xpdf/UnicodeMap.h +135 -0
  412. data/pdf2json-0.52-source/xpdf/UnicodeMap.h.old +123 -0
  413. data/pdf2json-0.52-source/xpdf/UnicodeMap.o +0 -0
  414. data/pdf2json-0.52-source/xpdf/UnicodeMapTables.h +361 -0
  415. data/pdf2json-0.52-source/xpdf/UnicodeTypeTable.cc +949 -0
  416. data/pdf2json-0.52-source/xpdf/UnicodeTypeTable.h +20 -0
  417. data/pdf2json-0.52-source/xpdf/UnicodeTypeTable.o +0 -0
  418. data/pdf2json-0.52-source/xpdf/XPDFApp.cc +447 -0
  419. data/pdf2json-0.52-source/xpdf/XPDFApp.h +114 -0
  420. data/pdf2json-0.52-source/xpdf/XPDFCore.cc +1655 -0
  421. data/pdf2json-0.52-source/xpdf/XPDFCore.h +251 -0
  422. data/pdf2json-0.52-source/xpdf/XPDFTree.cc +931 -0
  423. data/pdf2json-0.52-source/xpdf/XPDFTree.h +45 -0
  424. data/pdf2json-0.52-source/xpdf/XPDFTreeP.h +87 -0
  425. data/pdf2json-0.52-source/xpdf/XPDFViewer.cc +3488 -0
  426. data/pdf2json-0.52-source/xpdf/XPDFViewer.h +352 -0
  427. data/pdf2json-0.52-source/xpdf/XRef.cc +896 -0
  428. data/pdf2json-0.52-source/xpdf/XRef.h +133 -0
  429. data/pdf2json-0.52-source/xpdf/XRef.o +0 -0
  430. data/pdf2json-0.52-source/xpdf/XpdfPluginAPI.cc +262 -0
  431. data/pdf2json-0.52-source/xpdf/XpdfPluginAPI.h +341 -0
  432. data/pdf2json-0.52-source/xpdf/XpdfPluginAPI.o +0 -0
  433. data/pdf2json-0.52-source/xpdf/about-text.h +48 -0
  434. data/pdf2json-0.52-source/xpdf/about.xbm +6 -0
  435. data/pdf2json-0.52-source/xpdf/backArrow.xbm +6 -0
  436. data/pdf2json-0.52-source/xpdf/backArrowDis.xbm +6 -0
  437. data/pdf2json-0.52-source/xpdf/config.h +112 -0
  438. data/pdf2json-0.52-source/xpdf/dblLeftArrow.xbm +6 -0
  439. data/pdf2json-0.52-source/xpdf/dblLeftArrowDis.xbm +6 -0
  440. data/pdf2json-0.52-source/xpdf/dblRightArrow.xbm +6 -0
  441. data/pdf2json-0.52-source/xpdf/dblRightArrowDis.xbm +6 -0
  442. data/pdf2json-0.52-source/xpdf/find.xbm +6 -0
  443. data/pdf2json-0.52-source/xpdf/findDis.xbm +6 -0
  444. data/pdf2json-0.52-source/xpdf/forwardArrow.xbm +6 -0
  445. data/pdf2json-0.52-source/xpdf/forwardArrowDis.xbm +6 -0
  446. data/pdf2json-0.52-source/xpdf/leftArrow.xbm +5 -0
  447. data/pdf2json-0.52-source/xpdf/leftArrowDis.xbm +5 -0
  448. data/pdf2json-0.52-source/xpdf/libXpdf.a +0 -0
  449. data/pdf2json-0.52-source/xpdf/pdffonts +0 -0
  450. data/pdf2json-0.52-source/xpdf/pdffonts.cc +298 -0
  451. data/pdf2json-0.52-source/xpdf/pdffonts.o +0 -0
  452. data/pdf2json-0.52-source/xpdf/pdfimages +0 -0
  453. data/pdf2json-0.52-source/xpdf/pdfimages.cc +155 -0
  454. data/pdf2json-0.52-source/xpdf/pdfimages.o +0 -0
  455. data/pdf2json-0.52-source/xpdf/pdfinfo +0 -0
  456. data/pdf2json-0.52-source/xpdf/pdfinfo.cc +387 -0
  457. data/pdf2json-0.52-source/xpdf/pdfinfo.o +0 -0
  458. data/pdf2json-0.52-source/xpdf/pdftoppm.cc +203 -0
  459. data/pdf2json-0.52-source/xpdf/pdftops +0 -0
  460. data/pdf2json-0.52-source/xpdf/pdftops.cc +344 -0
  461. data/pdf2json-0.52-source/xpdf/pdftops.o +0 -0
  462. data/pdf2json-0.52-source/xpdf/pdftotext +0 -0
  463. data/pdf2json-0.52-source/xpdf/pdftotext.cc +333 -0
  464. data/pdf2json-0.52-source/xpdf/pdftotext.o +0 -0
  465. data/pdf2json-0.52-source/xpdf/print.xbm +6 -0
  466. data/pdf2json-0.52-source/xpdf/printDis.xbm +6 -0
  467. data/pdf2json-0.52-source/xpdf/rightArrow.xbm +5 -0
  468. data/pdf2json-0.52-source/xpdf/rightArrowDis.xbm +5 -0
  469. data/pdf2json-0.52-source/xpdf/vms_make.com +129 -0
  470. data/pdf2json-0.52-source/xpdf/xpdf.cc +344 -0
  471. data/pdf2json-0.52-source/xpdf/xpdfIcon.xpm +62 -0
  472. data/pdf2json.gemspec +29 -0
  473. metadata +518 -0
@@ -0,0 +1,229 @@
1
+ //========================================================================
2
+ //
3
+ // Function.h
4
+ //
5
+ // Copyright 2001-2003 Glyph & Cog, LLC
6
+ //
7
+ //========================================================================
8
+
9
+ #ifndef FUNCTION_H
10
+ #define FUNCTION_H
11
+
12
+ #include <aconf.h>
13
+
14
+ #ifdef USE_GCC_PRAGMAS
15
+ #pragma interface
16
+ #endif
17
+
18
+ #include "gtypes.h"
19
+ #include "Object.h"
20
+
21
+ class Dict;
22
+ class Stream;
23
+ struct PSObject;
24
+ class PSStack;
25
+
26
+ //------------------------------------------------------------------------
27
+ // Function
28
+ //------------------------------------------------------------------------
29
+
30
+ #define funcMaxInputs 32
31
+ #define funcMaxOutputs 32
32
+ #define sampledFuncMaxInputs 16
33
+
34
+ class Function {
35
+ public:
36
+
37
+ Function();
38
+
39
+ virtual ~Function();
40
+
41
+ // Construct a function. Returns NULL if unsuccessful.
42
+ static Function *parse(Object *funcObj);
43
+
44
+ // Initialize the entries common to all function types.
45
+ GBool init(Dict *dict);
46
+
47
+ virtual Function *copy() = 0;
48
+
49
+ // Return the function type:
50
+ // -1 : identity
51
+ // 0 : sampled
52
+ // 2 : exponential
53
+ // 3 : stitching
54
+ // 4 : PostScript
55
+ virtual int getType() = 0;
56
+
57
+ // Return size of input and output tuples.
58
+ int getInputSize() { return m; }
59
+ int getOutputSize() { return n; }
60
+
61
+ double getDomainMin(int i) { return domain[i][0]; }
62
+ double getDomainMax(int i) { return domain[i][1]; }
63
+ double getRangeMin(int i) { return range[i][0]; }
64
+ double getRangeMax(int i) { return range[i][1]; }
65
+ GBool getHasRange() { return hasRange; }
66
+
67
+ // Transform an input tuple into an output tuple.
68
+ virtual void transform(double *in, double *out) = 0;
69
+
70
+ virtual GBool isOk() = 0;
71
+
72
+ protected:
73
+
74
+ int m, n; // size of input and output tuples
75
+ double // min and max values for function domain
76
+ domain[funcMaxInputs][2];
77
+ double // min and max values for function range
78
+ range[funcMaxOutputs][2];
79
+ GBool hasRange; // set if range is defined
80
+ };
81
+
82
+ //------------------------------------------------------------------------
83
+ // IdentityFunction
84
+ //------------------------------------------------------------------------
85
+
86
+ class IdentityFunction: public Function {
87
+ public:
88
+
89
+ IdentityFunction();
90
+ virtual ~IdentityFunction();
91
+ virtual Function *copy() { return new IdentityFunction(); }
92
+ virtual int getType() { return -1; }
93
+ virtual void transform(double *in, double *out);
94
+ virtual GBool isOk() { return gTrue; }
95
+
96
+ private:
97
+ };
98
+
99
+ //------------------------------------------------------------------------
100
+ // SampledFunction
101
+ //------------------------------------------------------------------------
102
+
103
+ class SampledFunction: public Function {
104
+ public:
105
+
106
+ SampledFunction(Object *funcObj, Dict *dict);
107
+ virtual ~SampledFunction();
108
+ virtual Function *copy() { return new SampledFunction(this); }
109
+ virtual int getType() { return 0; }
110
+ virtual void transform(double *in, double *out);
111
+ virtual GBool isOk() { return ok; }
112
+
113
+ int getSampleSize(int i) { return sampleSize[i]; }
114
+ double getEncodeMin(int i) { return encode[i][0]; }
115
+ double getEncodeMax(int i) { return encode[i][1]; }
116
+ double getDecodeMin(int i) { return decode[i][0]; }
117
+ double getDecodeMax(int i) { return decode[i][1]; }
118
+ double *getSamples() { return samples; }
119
+
120
+ private:
121
+
122
+ SampledFunction(SampledFunction *func);
123
+
124
+ int // number of samples for each domain element
125
+ sampleSize[funcMaxInputs];
126
+ double // min and max values for domain encoder
127
+ encode[funcMaxInputs][2];
128
+ double // min and max values for range decoder
129
+ decode[funcMaxOutputs][2];
130
+ double // input multipliers
131
+ inputMul[funcMaxInputs];
132
+ int idxMul[funcMaxInputs]; // sample array index multipliers
133
+ double *samples; // the samples
134
+ int nSamples; // size of the samples array
135
+ double *sBuf; // buffer for the transform function
136
+ GBool ok;
137
+ };
138
+
139
+ //------------------------------------------------------------------------
140
+ // ExponentialFunction
141
+ //------------------------------------------------------------------------
142
+
143
+ class ExponentialFunction: public Function {
144
+ public:
145
+
146
+ ExponentialFunction(Object *funcObj, Dict *dict);
147
+ virtual ~ExponentialFunction();
148
+ virtual Function *copy() { return new ExponentialFunction(this); }
149
+ virtual int getType() { return 2; }
150
+ virtual void transform(double *in, double *out);
151
+ virtual GBool isOk() { return ok; }
152
+
153
+ double *getC0() { return c0; }
154
+ double *getC1() { return c1; }
155
+ double getE() { return e; }
156
+
157
+ private:
158
+
159
+ ExponentialFunction(ExponentialFunction *func);
160
+
161
+ double c0[funcMaxOutputs];
162
+ double c1[funcMaxOutputs];
163
+ double e;
164
+ GBool ok;
165
+ };
166
+
167
+ //------------------------------------------------------------------------
168
+ // StitchingFunction
169
+ //------------------------------------------------------------------------
170
+
171
+ class StitchingFunction: public Function {
172
+ public:
173
+
174
+ StitchingFunction(Object *funcObj, Dict *dict);
175
+ virtual ~StitchingFunction();
176
+ virtual Function *copy() { return new StitchingFunction(this); }
177
+ virtual int getType() { return 3; }
178
+ virtual void transform(double *in, double *out);
179
+ virtual GBool isOk() { return ok; }
180
+
181
+ int getNumFuncs() { return k; }
182
+ Function *getFunc(int i) { return funcs[i]; }
183
+ double *getBounds() { return bounds; }
184
+ double *getEncode() { return encode; }
185
+ double *getScale() { return scale; }
186
+
187
+ private:
188
+
189
+ StitchingFunction(StitchingFunction *func);
190
+
191
+ int k;
192
+ Function **funcs;
193
+ double *bounds;
194
+ double *encode;
195
+ double *scale;
196
+ GBool ok;
197
+ };
198
+
199
+ //------------------------------------------------------------------------
200
+ // PostScriptFunction
201
+ //------------------------------------------------------------------------
202
+
203
+ class PostScriptFunction: public Function {
204
+ public:
205
+
206
+ PostScriptFunction(Object *funcObj, Dict *dict);
207
+ virtual ~PostScriptFunction();
208
+ virtual Function *copy() { return new PostScriptFunction(this); }
209
+ virtual int getType() { return 4; }
210
+ virtual void transform(double *in, double *out);
211
+ virtual GBool isOk() { return ok; }
212
+
213
+ GString *getCodeString() { return codeString; }
214
+
215
+ private:
216
+
217
+ PostScriptFunction(PostScriptFunction *func);
218
+ GBool parseCode(Stream *str, int *codePtr);
219
+ GString *getToken(Stream *str);
220
+ void resizeCode(int newSize);
221
+ void exec(PSStack *stack, int codePtr);
222
+
223
+ GString *codeString;
224
+ PSObject *code;
225
+ int codeSize;
226
+ GBool ok;
227
+ };
228
+
229
+ #endif
@@ -0,0 +1,4187 @@
1
+ //========================================================================
2
+ //
3
+ // Gfx.cc
4
+ //
5
+ // Copyright 1996-2003 Glyph & Cog, LLC
6
+ //
7
+ //========================================================================
8
+
9
+ #include <aconf.h>
10
+
11
+ #ifdef USE_GCC_PRAGMAS
12
+ #pragma implementation
13
+ #endif
14
+
15
+ #include <stdlib.h>
16
+ #include <stdio.h>
17
+ #include <stddef.h>
18
+ #include <string.h>
19
+ #include <math.h>
20
+ #include "gmem.h"
21
+ #include "GlobalParams.h"
22
+ #include "CharTypes.h"
23
+ #include "Object.h"
24
+ #include "Array.h"
25
+ #include "Dict.h"
26
+ #include "Stream.h"
27
+ #include "Lexer.h"
28
+ #include "Parser.h"
29
+ #include "GfxFont.h"
30
+ #include "GfxState.h"
31
+ #include "OutputDev.h"
32
+ #include "Page.h"
33
+ #include "Annot.h"
34
+ #include "Error.h"
35
+ #include "Gfx.h"
36
+
37
+ // the MSVC math.h doesn't define this
38
+ #ifndef M_PI
39
+ #define M_PI 3.14159265358979323846
40
+ #endif
41
+
42
+ //------------------------------------------------------------------------
43
+ // constants
44
+ //------------------------------------------------------------------------
45
+
46
+ // Max recursive depth for a function shading fill.
47
+ #define functionMaxDepth 6
48
+
49
+ // Max delta allowed in any color component for a function shading fill.
50
+ #define functionColorDelta (dblToCol(1 / 256.0))
51
+
52
+ // Max number of splits along the t axis for an axial shading fill.
53
+ #define axialMaxSplits 256
54
+
55
+ // Max delta allowed in any color component for an axial shading fill.
56
+ #define axialColorDelta (dblToCol(1 / 256.0))
57
+
58
+ // Max number of splits along the t axis for a radial shading fill.
59
+ #define radialMaxSplits 256
60
+
61
+ // Max delta allowed in any color component for a radial shading fill.
62
+ #define radialColorDelta (dblToCol(1 / 256.0))
63
+
64
+ // Max recursive depth for a Gouraud triangle shading fill.
65
+ #define gouraudMaxDepth 6
66
+
67
+ // Max delta allowed in any color component for a Gouraud triangle
68
+ // shading fill.
69
+ #define gouraudColorDelta (dblToCol(1 / 256.0))
70
+
71
+ // Max recursive depth for a patch mesh shading fill.
72
+ #define patchMaxDepth 6
73
+
74
+ // Max delta allowed in any color component for a patch mesh shading
75
+ // fill.
76
+ #define patchColorDelta (dblToCol(1 / 256.0))
77
+
78
+ //------------------------------------------------------------------------
79
+ // Operator table
80
+ //------------------------------------------------------------------------
81
+
82
+ #ifdef WIN32 // this works around a bug in the VC7 compiler
83
+ # pragma optimize("",off)
84
+ #endif
85
+
86
+ Operator Gfx::opTab[] = {
87
+ {"\"", 3, {tchkNum, tchkNum, tchkString},
88
+ &Gfx::opMoveSetShowText},
89
+ {"'", 1, {tchkString},
90
+ &Gfx::opMoveShowText},
91
+ {"B", 0, {tchkNone},
92
+ &Gfx::opFillStroke},
93
+ {"B*", 0, {tchkNone},
94
+ &Gfx::opEOFillStroke},
95
+ {"BDC", 2, {tchkName, tchkProps},
96
+ &Gfx::opBeginMarkedContent},
97
+ {"BI", 0, {tchkNone},
98
+ &Gfx::opBeginImage},
99
+ {"BMC", 1, {tchkName},
100
+ &Gfx::opBeginMarkedContent},
101
+ {"BT", 0, {tchkNone},
102
+ &Gfx::opBeginText},
103
+ {"BX", 0, {tchkNone},
104
+ &Gfx::opBeginIgnoreUndef},
105
+ {"CS", 1, {tchkName},
106
+ &Gfx::opSetStrokeColorSpace},
107
+ {"DP", 2, {tchkName, tchkProps},
108
+ &Gfx::opMarkPoint},
109
+ {"Do", 1, {tchkName},
110
+ &Gfx::opXObject},
111
+ {"EI", 0, {tchkNone},
112
+ &Gfx::opEndImage},
113
+ {"EMC", 0, {tchkNone},
114
+ &Gfx::opEndMarkedContent},
115
+ {"ET", 0, {tchkNone},
116
+ &Gfx::opEndText},
117
+ {"EX", 0, {tchkNone},
118
+ &Gfx::opEndIgnoreUndef},
119
+ {"F", 0, {tchkNone},
120
+ &Gfx::opFill},
121
+ {"G", 1, {tchkNum},
122
+ &Gfx::opSetStrokeGray},
123
+ {"ID", 0, {tchkNone},
124
+ &Gfx::opImageData},
125
+ {"J", 1, {tchkInt},
126
+ &Gfx::opSetLineCap},
127
+ {"K", 4, {tchkNum, tchkNum, tchkNum, tchkNum},
128
+ &Gfx::opSetStrokeCMYKColor},
129
+ {"M", 1, {tchkNum},
130
+ &Gfx::opSetMiterLimit},
131
+ {"MP", 1, {tchkName},
132
+ &Gfx::opMarkPoint},
133
+ {"Q", 0, {tchkNone},
134
+ &Gfx::opRestore},
135
+ {"RG", 3, {tchkNum, tchkNum, tchkNum},
136
+ &Gfx::opSetStrokeRGBColor},
137
+ {"S", 0, {tchkNone},
138
+ &Gfx::opStroke},
139
+ {"SC", -4, {tchkNum, tchkNum, tchkNum, tchkNum},
140
+ &Gfx::opSetStrokeColor},
141
+ {"SCN", -33, {tchkSCN, tchkSCN, tchkSCN, tchkSCN,
142
+ tchkSCN, tchkSCN, tchkSCN, tchkSCN,
143
+ tchkSCN, tchkSCN, tchkSCN, tchkSCN,
144
+ tchkSCN, tchkSCN, tchkSCN, tchkSCN,
145
+ tchkSCN, tchkSCN, tchkSCN, tchkSCN,
146
+ tchkSCN, tchkSCN, tchkSCN, tchkSCN,
147
+ tchkSCN, tchkSCN, tchkSCN, tchkSCN,
148
+ tchkSCN, tchkSCN, tchkSCN, tchkSCN,
149
+ tchkSCN},
150
+ &Gfx::opSetStrokeColorN},
151
+ {"T*", 0, {tchkNone},
152
+ &Gfx::opTextNextLine},
153
+ {"TD", 2, {tchkNum, tchkNum},
154
+ &Gfx::opTextMoveSet},
155
+ {"TJ", 1, {tchkArray},
156
+ &Gfx::opShowSpaceText},
157
+ {"TL", 1, {tchkNum},
158
+ &Gfx::opSetTextLeading},
159
+ {"Tc", 1, {tchkNum},
160
+ &Gfx::opSetCharSpacing},
161
+ {"Td", 2, {tchkNum, tchkNum},
162
+ &Gfx::opTextMove},
163
+ {"Tf", 2, {tchkName, tchkNum},
164
+ &Gfx::opSetFont},
165
+ {"Tj", 1, {tchkString},
166
+ &Gfx::opShowText},
167
+ {"Tm", 6, {tchkNum, tchkNum, tchkNum, tchkNum,
168
+ tchkNum, tchkNum},
169
+ &Gfx::opSetTextMatrix},
170
+ {"Tr", 1, {tchkInt},
171
+ &Gfx::opSetTextRender},
172
+ {"Ts", 1, {tchkNum},
173
+ &Gfx::opSetTextRise},
174
+ {"Tw", 1, {tchkNum},
175
+ &Gfx::opSetWordSpacing},
176
+ {"Tz", 1, {tchkNum},
177
+ &Gfx::opSetHorizScaling},
178
+ {"W", 0, {tchkNone},
179
+ &Gfx::opClip},
180
+ {"W*", 0, {tchkNone},
181
+ &Gfx::opEOClip},
182
+ {"b", 0, {tchkNone},
183
+ &Gfx::opCloseFillStroke},
184
+ {"b*", 0, {tchkNone},
185
+ &Gfx::opCloseEOFillStroke},
186
+ {"c", 6, {tchkNum, tchkNum, tchkNum, tchkNum,
187
+ tchkNum, tchkNum},
188
+ &Gfx::opCurveTo},
189
+ {"cm", 6, {tchkNum, tchkNum, tchkNum, tchkNum,
190
+ tchkNum, tchkNum},
191
+ &Gfx::opConcat},
192
+ {"cs", 1, {tchkName},
193
+ &Gfx::opSetFillColorSpace},
194
+ {"d", 2, {tchkArray, tchkNum},
195
+ &Gfx::opSetDash},
196
+ {"d0", 2, {tchkNum, tchkNum},
197
+ &Gfx::opSetCharWidth},
198
+ {"d1", 6, {tchkNum, tchkNum, tchkNum, tchkNum,
199
+ tchkNum, tchkNum},
200
+ &Gfx::opSetCacheDevice},
201
+ {"f", 0, {tchkNone},
202
+ &Gfx::opFill},
203
+ {"f*", 0, {tchkNone},
204
+ &Gfx::opEOFill},
205
+ {"g", 1, {tchkNum},
206
+ &Gfx::opSetFillGray},
207
+ {"gs", 1, {tchkName},
208
+ &Gfx::opSetExtGState},
209
+ {"h", 0, {tchkNone},
210
+ &Gfx::opClosePath},
211
+ {"i", 1, {tchkNum},
212
+ &Gfx::opSetFlat},
213
+ {"j", 1, {tchkInt},
214
+ &Gfx::opSetLineJoin},
215
+ {"k", 4, {tchkNum, tchkNum, tchkNum, tchkNum},
216
+ &Gfx::opSetFillCMYKColor},
217
+ {"l", 2, {tchkNum, tchkNum},
218
+ &Gfx::opLineTo},
219
+ {"m", 2, {tchkNum, tchkNum},
220
+ &Gfx::opMoveTo},
221
+ {"n", 0, {tchkNone},
222
+ &Gfx::opEndPath},
223
+ {"q", 0, {tchkNone},
224
+ &Gfx::opSave},
225
+ {"re", 4, {tchkNum, tchkNum, tchkNum, tchkNum},
226
+ &Gfx::opRectangle},
227
+ {"rg", 3, {tchkNum, tchkNum, tchkNum},
228
+ &Gfx::opSetFillRGBColor},
229
+ {"ri", 1, {tchkName},
230
+ &Gfx::opSetRenderingIntent},
231
+ {"s", 0, {tchkNone},
232
+ &Gfx::opCloseStroke},
233
+ {"sc", -4, {tchkNum, tchkNum, tchkNum, tchkNum},
234
+ &Gfx::opSetFillColor},
235
+ {"scn", -33, {tchkSCN, tchkSCN, tchkSCN, tchkSCN,
236
+ tchkSCN, tchkSCN, tchkSCN, tchkSCN,
237
+ tchkSCN, tchkSCN, tchkSCN, tchkSCN,
238
+ tchkSCN, tchkSCN, tchkSCN, tchkSCN,
239
+ tchkSCN, tchkSCN, tchkSCN, tchkSCN,
240
+ tchkSCN, tchkSCN, tchkSCN, tchkSCN,
241
+ tchkSCN, tchkSCN, tchkSCN, tchkSCN,
242
+ tchkSCN, tchkSCN, tchkSCN, tchkSCN,
243
+ tchkSCN},
244
+ &Gfx::opSetFillColorN},
245
+ {"sh", 1, {tchkName},
246
+ &Gfx::opShFill},
247
+ {"v", 4, {tchkNum, tchkNum, tchkNum, tchkNum},
248
+ &Gfx::opCurveTo1},
249
+ {"w", 1, {tchkNum},
250
+ &Gfx::opSetLineWidth},
251
+ {"y", 4, {tchkNum, tchkNum, tchkNum, tchkNum},
252
+ &Gfx::opCurveTo2},
253
+ };
254
+
255
+ #ifdef WIN32 // this works around a bug in the VC7 compiler
256
+ # pragma optimize("",on)
257
+ #endif
258
+
259
+ #define numOps (sizeof(opTab) / sizeof(Operator))
260
+
261
+ //------------------------------------------------------------------------
262
+ // GfxResources
263
+ //------------------------------------------------------------------------
264
+
265
+ GfxResources::GfxResources(XRef *xref, Dict *resDict, GfxResources *nextA) {
266
+ Object obj1, obj2;
267
+ Ref r;
268
+
269
+ if (resDict) {
270
+
271
+ // build font dictionary
272
+ fonts = NULL;
273
+ resDict->lookupNF("Font", &obj1);
274
+ if (obj1.isRef()) {
275
+ obj1.fetch(xref, &obj2);
276
+ if (obj2.isDict()) {
277
+ r = obj1.getRef();
278
+ fonts = new GfxFontDict(xref, &r, obj2.getDict());
279
+ }
280
+ obj2.free();
281
+ } else if (obj1.isDict()) {
282
+ fonts = new GfxFontDict(xref, NULL, obj1.getDict());
283
+ }
284
+ obj1.free();
285
+
286
+ // get XObject dictionary
287
+ resDict->lookup("XObject", &xObjDict);
288
+
289
+ // get color space dictionary
290
+ resDict->lookup("ColorSpace", &colorSpaceDict);
291
+
292
+ // get pattern dictionary
293
+ resDict->lookup("Pattern", &patternDict);
294
+
295
+ // get shading dictionary
296
+ resDict->lookup("Shading", &shadingDict);
297
+
298
+ // get graphics state parameter dictionary
299
+ resDict->lookup("ExtGState", &gStateDict);
300
+
301
+ } else {
302
+ fonts = NULL;
303
+ xObjDict.initNull();
304
+ colorSpaceDict.initNull();
305
+ patternDict.initNull();
306
+ shadingDict.initNull();
307
+ gStateDict.initNull();
308
+ }
309
+
310
+ next = nextA;
311
+ }
312
+
313
+ GfxResources::~GfxResources() {
314
+ if (fonts) {
315
+ delete fonts;
316
+ }
317
+ xObjDict.free();
318
+ colorSpaceDict.free();
319
+ patternDict.free();
320
+ shadingDict.free();
321
+ gStateDict.free();
322
+ }
323
+
324
+ GfxFont *GfxResources::lookupFont(char *name) {
325
+ GfxFont *font;
326
+ GfxResources *resPtr;
327
+
328
+ for (resPtr = this; resPtr; resPtr = resPtr->next) {
329
+ if (resPtr->fonts) {
330
+ if ((font = resPtr->fonts->lookup(name)))
331
+ return font;
332
+ }
333
+ }
334
+ error(-1, "Unknown font tag '%s'", name);
335
+ return NULL;
336
+ }
337
+
338
+ GBool GfxResources::lookupXObject(char *name, Object *obj) {
339
+ GfxResources *resPtr;
340
+
341
+ for (resPtr = this; resPtr; resPtr = resPtr->next) {
342
+ if (resPtr->xObjDict.isDict()) {
343
+ if (!resPtr->xObjDict.dictLookup(name, obj)->isNull())
344
+ return gTrue;
345
+ obj->free();
346
+ }
347
+ }
348
+ error(-1, "XObject '%s' is unknown", name);
349
+ return gFalse;
350
+ }
351
+
352
+ GBool GfxResources::lookupXObjectNF(char *name, Object *obj) {
353
+ GfxResources *resPtr;
354
+
355
+ for (resPtr = this; resPtr; resPtr = resPtr->next) {
356
+ if (resPtr->xObjDict.isDict()) {
357
+ if (!resPtr->xObjDict.dictLookupNF(name, obj)->isNull())
358
+ return gTrue;
359
+ obj->free();
360
+ }
361
+ }
362
+ error(-1, "XObject '%s' is unknown", name);
363
+ return gFalse;
364
+ }
365
+
366
+ void GfxResources::lookupColorSpace(char *name, Object *obj) {
367
+ GfxResources *resPtr;
368
+
369
+ for (resPtr = this; resPtr; resPtr = resPtr->next) {
370
+ if (resPtr->colorSpaceDict.isDict()) {
371
+ if (!resPtr->colorSpaceDict.dictLookup(name, obj)->isNull()) {
372
+ return;
373
+ }
374
+ obj->free();
375
+ }
376
+ }
377
+ obj->initNull();
378
+ }
379
+
380
+ GfxPattern *GfxResources::lookupPattern(char *name) {
381
+ GfxResources *resPtr;
382
+ GfxPattern *pattern;
383
+ Object obj;
384
+
385
+ for (resPtr = this; resPtr; resPtr = resPtr->next) {
386
+ if (resPtr->patternDict.isDict()) {
387
+ if (!resPtr->patternDict.dictLookup(name, &obj)->isNull()) {
388
+ pattern = GfxPattern::parse(&obj);
389
+ obj.free();
390
+ return pattern;
391
+ }
392
+ obj.free();
393
+ }
394
+ }
395
+ error(-1, "Unknown pattern '%s'", name);
396
+ return NULL;
397
+ }
398
+
399
+ GfxShading *GfxResources::lookupShading(char *name) {
400
+ GfxResources *resPtr;
401
+ GfxShading *shading;
402
+ Object obj;
403
+
404
+ for (resPtr = this; resPtr; resPtr = resPtr->next) {
405
+ if (resPtr->shadingDict.isDict()) {
406
+ if (!resPtr->shadingDict.dictLookup(name, &obj)->isNull()) {
407
+ shading = GfxShading::parse(&obj);
408
+ obj.free();
409
+ return shading;
410
+ }
411
+ obj.free();
412
+ }
413
+ }
414
+ error(-1, "Unknown shading '%s'", name);
415
+ return NULL;
416
+ }
417
+
418
+ GBool GfxResources::lookupGState(char *name, Object *obj) {
419
+ GfxResources *resPtr;
420
+
421
+ for (resPtr = this; resPtr; resPtr = resPtr->next) {
422
+ if (resPtr->gStateDict.isDict()) {
423
+ if (!resPtr->gStateDict.dictLookup(name, obj)->isNull()) {
424
+ return gTrue;
425
+ }
426
+ obj->free();
427
+ }
428
+ }
429
+ error(-1, "ExtGState '%s' is unknown", name);
430
+ return gFalse;
431
+ }
432
+
433
+ //------------------------------------------------------------------------
434
+ // Gfx
435
+ //------------------------------------------------------------------------
436
+
437
+ Gfx::Gfx(XRef *xrefA, OutputDev *outA, int pageNum, Dict *resDict,
438
+ double hDPI, double vDPI, PDFRectangle *box,
439
+ PDFRectangle *cropBox, int rotate,
440
+ GBool (*abortCheckCbkA)(void *data),
441
+ void *abortCheckCbkDataA) {
442
+ int i;
443
+
444
+ xref = xrefA;
445
+ subPage = gFalse;
446
+ printCommands = globalParams->getPrintCommands();
447
+
448
+ // start the resource stack
449
+ res = new GfxResources(xref, resDict, NULL);
450
+
451
+ // initialize
452
+ out = outA;
453
+ state = new GfxState(hDPI, vDPI, box, rotate, out->upsideDown());
454
+ fontChanged = gFalse;
455
+ clip = clipNone;
456
+ ignoreUndef = 0;
457
+ // out->startPage(pageNum, state);
458
+ if(cropBox) {
459
+ out->startPage(pageNum, state, cropBox->x1,cropBox->y1,cropBox->x2,cropBox->y2);
460
+ } else {
461
+ out->startPage(pageNum, state, 0,0,0,0);
462
+ }
463
+
464
+ out->setDefaultCTM(state->getCTM());
465
+ out->updateAll(state);
466
+ for (i = 0; i < 6; ++i) {
467
+ baseMatrix[i] = state->getCTM()[i];
468
+ }
469
+ formDepth = 0;
470
+ abortCheckCbk = abortCheckCbkA;
471
+ abortCheckCbkData = abortCheckCbkDataA;
472
+
473
+ // set crop box
474
+ if (cropBox) {
475
+ state->moveTo(cropBox->x1, cropBox->y1);
476
+ state->lineTo(cropBox->x2, cropBox->y1);
477
+ state->lineTo(cropBox->x2, cropBox->y2);
478
+ state->lineTo(cropBox->x1, cropBox->y2);
479
+ state->closePath();
480
+ state->clip();
481
+ out->clip(state);
482
+ state->clearPath();
483
+ }
484
+ }
485
+
486
+ Gfx::Gfx(XRef *xrefA, OutputDev *outA, Dict *resDict,
487
+ PDFRectangle *box, PDFRectangle *cropBox,
488
+ GBool (*abortCheckCbkA)(void *data),
489
+ void *abortCheckCbkDataA) {
490
+ int i;
491
+
492
+ xref = xrefA;
493
+ subPage = gTrue;
494
+ printCommands = globalParams->getPrintCommands();
495
+
496
+ // start the resource stack
497
+ res = new GfxResources(xref, resDict, NULL);
498
+
499
+ // initialize
500
+ out = outA;
501
+ state = new GfxState(72, 72, box, 0, gFalse);
502
+ fontChanged = gFalse;
503
+ clip = clipNone;
504
+ ignoreUndef = 0;
505
+ for (i = 0; i < 6; ++i) {
506
+ baseMatrix[i] = state->getCTM()[i];
507
+ }
508
+ formDepth = 0;
509
+ abortCheckCbk = abortCheckCbkA;
510
+ abortCheckCbkData = abortCheckCbkDataA;
511
+
512
+ // set crop box
513
+ if (cropBox) {
514
+ state->moveTo(cropBox->x1, cropBox->y1);
515
+ state->lineTo(cropBox->x2, cropBox->y1);
516
+ state->lineTo(cropBox->x2, cropBox->y2);
517
+ state->lineTo(cropBox->x1, cropBox->y2);
518
+ state->closePath();
519
+ state->clip();
520
+ out->clip(state);
521
+ state->clearPath();
522
+ }
523
+ }
524
+
525
+ Gfx::~Gfx() {
526
+ while (state->hasSaves()) {
527
+ restoreState();
528
+ }
529
+ if (!subPage) {
530
+ out->endPage();
531
+ }
532
+ while (res) {
533
+ popResources();
534
+ }
535
+ if (state) {
536
+ delete state;
537
+ }
538
+ }
539
+
540
+ void Gfx::display(Object *obj, GBool topLevel) {
541
+ Object obj2;
542
+ int i;
543
+
544
+ if (obj->isArray()) {
545
+ for (i = 0; i < obj->arrayGetLength(); ++i) {
546
+ obj->arrayGet(i, &obj2);
547
+ if (!obj2.isStream()) {
548
+ error(-1, "Weird page contents");
549
+ obj2.free();
550
+ return;
551
+ }
552
+ obj2.free();
553
+ }
554
+ } else if (!obj->isStream()) {
555
+ error(-1, "Weird page contents");
556
+ return;
557
+ }
558
+ parser = new Parser(xref, new Lexer(xref, obj), gFalse);
559
+ go(topLevel);
560
+ delete parser;
561
+ parser = NULL;
562
+ }
563
+
564
+ void Gfx::go(GBool topLevel) {
565
+ Object obj;
566
+ Object args[maxArgs];
567
+ int numArgs, i;
568
+ int lastAbortCheck;
569
+
570
+ // scan a sequence of objects
571
+ updateLevel = lastAbortCheck = 0;
572
+ numArgs = 0;
573
+ parser->getObj(&obj);
574
+ while (!obj.isEOF()) {
575
+
576
+ // got a command - execute it
577
+ if (obj.isCmd()) {
578
+ if (printCommands) {
579
+ obj.print(stdout);
580
+ for (i = 0; i < numArgs; ++i) {
581
+ printf(" ");
582
+ args[i].print(stdout);
583
+ }
584
+ printf("\n");
585
+ fflush(stdout);
586
+ }
587
+ execOp(&obj, args, numArgs);
588
+ obj.free();
589
+ for (i = 0; i < numArgs; ++i)
590
+ args[i].free();
591
+ numArgs = 0;
592
+
593
+ // periodically update display
594
+ if (++updateLevel >= 20000) {
595
+ out->dump();
596
+ updateLevel = 0;
597
+ }
598
+
599
+ // check for an abort
600
+ if (abortCheckCbk) {
601
+ if (updateLevel - lastAbortCheck > 10) {
602
+ if ((*abortCheckCbk)(abortCheckCbkData)) {
603
+ break;
604
+ }
605
+ lastAbortCheck = updateLevel;
606
+ }
607
+ }
608
+
609
+ // got an argument - save it
610
+ } else if (numArgs < maxArgs) {
611
+ args[numArgs++] = obj;
612
+
613
+ // too many arguments - something is wrong
614
+ } else {
615
+ error(getPos(), "Too many args in content stream");
616
+ if (printCommands) {
617
+ printf("throwing away arg: ");
618
+ obj.print(stdout);
619
+ printf("\n");
620
+ fflush(stdout);
621
+ }
622
+ obj.free();
623
+ }
624
+
625
+ // grab the next object
626
+ parser->getObj(&obj);
627
+ }
628
+ obj.free();
629
+
630
+ // args at end with no command
631
+ if (numArgs > 0) {
632
+ error(getPos(), "Leftover args in content stream");
633
+ if (printCommands) {
634
+ printf("%d leftovers:", numArgs);
635
+ for (i = 0; i < numArgs; ++i) {
636
+ printf(" ");
637
+ args[i].print(stdout);
638
+ }
639
+ printf("\n");
640
+ fflush(stdout);
641
+ }
642
+ for (i = 0; i < numArgs; ++i)
643
+ args[i].free();
644
+ }
645
+
646
+ // update display
647
+ if (topLevel && updateLevel > 0) {
648
+ out->dump();
649
+ }
650
+ }
651
+
652
+ void Gfx::execOp(Object *cmd, Object args[], int numArgs) {
653
+ Operator *op;
654
+ char *name;
655
+ Object *argPtr;
656
+ int i;
657
+
658
+ // find operator
659
+ name = cmd->getCmd();
660
+ if (!(op = findOp(name))) {
661
+ if (ignoreUndef == 0)
662
+ error(getPos(), "Unknown operator '%s'", name);
663
+ return;
664
+ }
665
+
666
+ // type check args
667
+ argPtr = args;
668
+ if (op->numArgs >= 0) {
669
+ if (numArgs < op->numArgs) {
670
+ error(getPos(), "Too few (%d) args to '%s' operator", numArgs, name);
671
+ return;
672
+ }
673
+ if (numArgs > op->numArgs) {
674
+ #if 0
675
+ error(getPos(), "Too many (%d) args to '%s' operator", numArgs, name);
676
+ #endif
677
+ argPtr += numArgs - op->numArgs;
678
+ numArgs = op->numArgs;
679
+ }
680
+ } else {
681
+ if (numArgs > -op->numArgs) {
682
+ error(getPos(), "Too many (%d) args to '%s' operator",
683
+ numArgs, name);
684
+ return;
685
+ }
686
+ }
687
+ for (i = 0; i < numArgs; ++i) {
688
+ if (!checkArg(&argPtr[i], op->tchk[i])) {
689
+ error(getPos(), "Arg #%d to '%s' operator is wrong type (%s)",
690
+ i, name, argPtr[i].getTypeName());
691
+ return;
692
+ }
693
+ }
694
+
695
+ // do it
696
+ (this->*op->func)(argPtr, numArgs);
697
+ }
698
+
699
+ Operator *Gfx::findOp(char *name) {
700
+ int a, b, m, cmp;
701
+
702
+ a = -1;
703
+ b = numOps;
704
+ // invariant: opTab[a] < name < opTab[b]
705
+ while (b - a > 1) {
706
+ m = (a + b) / 2;
707
+ cmp = strcmp(opTab[m].name, name);
708
+ if (cmp < 0)
709
+ a = m;
710
+ else if (cmp > 0)
711
+ b = m;
712
+ else
713
+ a = b = m;
714
+ }
715
+ if (cmp != 0)
716
+ return NULL;
717
+ return &opTab[a];
718
+ }
719
+
720
+ GBool Gfx::checkArg(Object *arg, TchkType type) {
721
+ switch (type) {
722
+ case tchkBool: return arg->isBool();
723
+ case tchkInt: return arg->isInt();
724
+ case tchkNum: return arg->isNum();
725
+ case tchkString: return arg->isString();
726
+ case tchkName: return arg->isName();
727
+ case tchkArray: return arg->isArray();
728
+ case tchkProps: return arg->isDict() || arg->isName();
729
+ case tchkSCN: return arg->isNum() || arg->isName();
730
+ case tchkNone: return gFalse;
731
+ }
732
+ return gFalse;
733
+ }
734
+
735
+ int Gfx::getPos() {
736
+ return parser ? parser->getPos() : -1;
737
+ }
738
+
739
+ //------------------------------------------------------------------------
740
+ // graphics state operators
741
+ //------------------------------------------------------------------------
742
+
743
+ void Gfx::opSave(Object args[], int numArgs) {
744
+ saveState();
745
+ }
746
+
747
+ void Gfx::opRestore(Object args[], int numArgs) {
748
+ restoreState();
749
+ }
750
+
751
+ void Gfx::opConcat(Object args[], int numArgs) {
752
+ state->concatCTM(args[0].getNum(), args[1].getNum(),
753
+ args[2].getNum(), args[3].getNum(),
754
+ args[4].getNum(), args[5].getNum());
755
+ out->updateCTM(state, args[0].getNum(), args[1].getNum(),
756
+ args[2].getNum(), args[3].getNum(),
757
+ args[4].getNum(), args[5].getNum());
758
+ fontChanged = gTrue;
759
+ }
760
+
761
+ void Gfx::opSetDash(Object args[], int numArgs) {
762
+ Array *a;
763
+ int length;
764
+ Object obj;
765
+ double *dash;
766
+ int i;
767
+
768
+ a = args[0].getArray();
769
+ length = a->getLength();
770
+ if (length == 0) {
771
+ dash = NULL;
772
+ } else {
773
+ dash = (double *)gmallocn(length, sizeof(double));
774
+ for (i = 0; i < length; ++i) {
775
+ dash[i] = a->get(i, &obj)->getNum();
776
+ obj.free();
777
+ }
778
+ }
779
+ state->setLineDash(dash, length, args[1].getNum());
780
+ out->updateLineDash(state);
781
+ }
782
+
783
+ void Gfx::opSetFlat(Object args[], int numArgs) {
784
+ state->setFlatness((int)args[0].getNum());
785
+ out->updateFlatness(state);
786
+ }
787
+
788
+ void Gfx::opSetLineJoin(Object args[], int numArgs) {
789
+ state->setLineJoin(args[0].getInt());
790
+ out->updateLineJoin(state);
791
+ }
792
+
793
+ void Gfx::opSetLineCap(Object args[], int numArgs) {
794
+ state->setLineCap(args[0].getInt());
795
+ out->updateLineCap(state);
796
+ }
797
+
798
+ void Gfx::opSetMiterLimit(Object args[], int numArgs) {
799
+ state->setMiterLimit(args[0].getNum());
800
+ out->updateMiterLimit(state);
801
+ }
802
+
803
+ void Gfx::opSetLineWidth(Object args[], int numArgs) {
804
+ state->setLineWidth(args[0].getNum());
805
+ out->updateLineWidth(state);
806
+ }
807
+
808
+ void Gfx::opSetExtGState(Object args[], int numArgs) {
809
+ Object obj1, obj2, obj3, obj4, obj5;
810
+ GfxBlendMode mode;
811
+ GBool haveFillOP;
812
+ Function *funcs[4];
813
+ GfxColor backdropColor;
814
+ GBool haveBackdropColor;
815
+ GfxColorSpace *blendingColorSpace;
816
+ GBool alpha, isolated, knockout;
817
+ int i;
818
+
819
+ if (!res->lookupGState(args[0].getName(), &obj1)) {
820
+ return;
821
+ }
822
+ if (!obj1.isDict()) {
823
+ error(getPos(), "ExtGState '%s' is wrong type", args[0].getName());
824
+ obj1.free();
825
+ return;
826
+ }
827
+ if (printCommands) {
828
+ printf(" gfx state dict: ");
829
+ obj1.print();
830
+ printf("\n");
831
+ }
832
+
833
+ // transparency support: blend mode, fill/stroke opacity
834
+ if (!obj1.dictLookup("BM", &obj2)->isNull()) {
835
+ if (state->parseBlendMode(&obj2, &mode)) {
836
+ state->setBlendMode(mode);
837
+ out->updateBlendMode(state);
838
+ } else {
839
+ error(getPos(), "Invalid blend mode in ExtGState");
840
+ }
841
+ }
842
+ obj2.free();
843
+ if (obj1.dictLookup("ca", &obj2)->isNum()) {
844
+ state->setFillOpacity(obj2.getNum());
845
+ out->updateFillOpacity(state);
846
+ }
847
+ obj2.free();
848
+ if (obj1.dictLookup("CA", &obj2)->isNum()) {
849
+ state->setStrokeOpacity(obj2.getNum());
850
+ out->updateStrokeOpacity(state);
851
+ }
852
+ obj2.free();
853
+
854
+ // fill/stroke overprint
855
+ if ((haveFillOP = (obj1.dictLookup("op", &obj2)->isBool()))) {
856
+ state->setFillOverprint(obj2.getBool());
857
+ out->updateFillOverprint(state);
858
+ }
859
+ obj2.free();
860
+ if (obj1.dictLookup("OP", &obj2)->isBool()) {
861
+ state->setStrokeOverprint(obj2.getBool());
862
+ out->updateStrokeOverprint(state);
863
+ if (!haveFillOP) {
864
+ state->setFillOverprint(obj2.getBool());
865
+ out->updateFillOverprint(state);
866
+ }
867
+ }
868
+ obj2.free();
869
+
870
+ // stroke adjust
871
+ if (obj1.dictLookup("SA", &obj2)->isBool()) {
872
+ state->setStrokeAdjust(obj2.getBool());
873
+ out->updateStrokeAdjust(state);
874
+ }
875
+ obj2.free();
876
+
877
+ // transfer function
878
+ if (obj1.dictLookup("TR2", &obj2)->isNull()) {
879
+ obj2.free();
880
+ obj1.dictLookup("TR", &obj2);
881
+ }
882
+ if (obj2.isName("Default") ||
883
+ obj2.isName("Identity")) {
884
+ funcs[0] = funcs[1] = funcs[2] = funcs[3] = NULL;
885
+ state->setTransfer(funcs);
886
+ out->updateTransfer(state);
887
+ } else if (obj2.isArray() && obj2.arrayGetLength() == 4) {
888
+ for (i = 0; i < 4; ++i) {
889
+ obj2.arrayGet(i, &obj3);
890
+ funcs[i] = Function::parse(&obj3);
891
+ obj3.free();
892
+ if (!funcs[i]) {
893
+ break;
894
+ }
895
+ }
896
+ if (i == 4) {
897
+ state->setTransfer(funcs);
898
+ out->updateTransfer(state);
899
+ }
900
+ } else if (obj2.isName() || obj2.isDict() || obj2.isStream()) {
901
+ if ((funcs[0] = Function::parse(&obj2))) {
902
+ funcs[1] = funcs[2] = funcs[3] = NULL;
903
+ state->setTransfer(funcs);
904
+ out->updateTransfer(state);
905
+ }
906
+ } else if (!obj2.isNull()) {
907
+ error(getPos(), "Invalid transfer function in ExtGState");
908
+ }
909
+ obj2.free();
910
+
911
+ // soft mask
912
+ if (!obj1.dictLookup("SMask", &obj2)->isNull()) {
913
+ if (obj2.isName("None")) {
914
+ out->clearSoftMask(state);
915
+ } else if (obj2.isDict()) {
916
+ if (obj2.dictLookup("S", &obj3)->isName("Alpha")) {
917
+ alpha = gTrue;
918
+ } else { // "Luminosity"
919
+ alpha = gFalse;
920
+ }
921
+ obj3.free();
922
+ funcs[0] = NULL;
923
+ if (!obj2.dictLookup("TR", &obj3)->isNull()) {
924
+ funcs[0] = Function::parse(&obj3);
925
+ if (funcs[0]->getInputSize() != 1 ||
926
+ funcs[0]->getOutputSize() != 1) {
927
+ error(getPos(),
928
+ "Invalid transfer function in soft mask in ExtGState");
929
+ delete funcs[0];
930
+ funcs[0] = NULL;
931
+ }
932
+ }
933
+ obj3.free();
934
+ if ((haveBackdropColor = obj2.dictLookup("BC", &obj3)->isArray())) {
935
+ for (i = 0; i < gfxColorMaxComps; ++i) {
936
+ backdropColor.c[i] = 0;
937
+ }
938
+ for (i = 0; i < obj3.arrayGetLength() && i < gfxColorMaxComps; ++i) {
939
+ obj3.arrayGet(i, &obj4);
940
+ if (obj4.isNum()) {
941
+ backdropColor.c[i] = dblToCol(obj4.getNum());
942
+ }
943
+ obj4.free();
944
+ }
945
+ }
946
+ obj3.free();
947
+ if (obj2.dictLookup("G", &obj3)->isStream()) {
948
+ if (obj3.streamGetDict()->lookup("Group", &obj4)->isDict()) {
949
+ blendingColorSpace = NULL;
950
+ isolated = knockout = gFalse;
951
+ if (!obj4.dictLookup("CS", &obj5)->isNull()) {
952
+ blendingColorSpace = GfxColorSpace::parse(&obj5);
953
+ }
954
+ obj5.free();
955
+ if (obj4.dictLookup("I", &obj5)->isBool()) {
956
+ isolated = obj5.getBool();
957
+ }
958
+ obj5.free();
959
+ if (obj4.dictLookup("K", &obj5)->isBool()) {
960
+ knockout = obj5.getBool();
961
+ }
962
+ obj5.free();
963
+ if (!haveBackdropColor) {
964
+ if (blendingColorSpace) {
965
+ blendingColorSpace->getDefaultColor(&backdropColor);
966
+ } else {
967
+ //~ need to get the parent or default color space (?)
968
+ for (i = 0; i < gfxColorMaxComps; ++i) {
969
+ backdropColor.c[i] = 0;
970
+ }
971
+ }
972
+ }
973
+ doSoftMask(&obj3, alpha, blendingColorSpace,
974
+ isolated, knockout, funcs[0], &backdropColor);
975
+ if (funcs[0]) {
976
+ delete funcs[0];
977
+ }
978
+ } else {
979
+ error(getPos(), "Invalid soft mask in ExtGState - missing group");
980
+ }
981
+ obj4.free();
982
+ } else {
983
+ error(getPos(), "Invalid soft mask in ExtGState - missing group");
984
+ }
985
+ obj3.free();
986
+ } else if (!obj2.isNull()) {
987
+ error(getPos(), "Invalid soft mask in ExtGState");
988
+ }
989
+ }
990
+ obj2.free();
991
+
992
+ obj1.free();
993
+ }
994
+
995
+ void Gfx::doSoftMask(Object *str, GBool alpha,
996
+ GfxColorSpace *blendingColorSpace,
997
+ GBool isolated, GBool knockout,
998
+ Function *transferFunc, GfxColor *backdropColor) {
999
+ Dict *dict, *resDict;
1000
+ double m[6], bbox[4];
1001
+ Object obj1, obj2;
1002
+ int i;
1003
+
1004
+ // check for excessive recursion
1005
+ if (formDepth > 20) {
1006
+ return;
1007
+ }
1008
+
1009
+ // get stream dict
1010
+ dict = str->streamGetDict();
1011
+
1012
+ // check form type
1013
+ dict->lookup("FormType", &obj1);
1014
+ if (!(obj1.isNull() || (obj1.isInt() && obj1.getInt() == 1))) {
1015
+ error(getPos(), "Unknown form type");
1016
+ }
1017
+ obj1.free();
1018
+
1019
+ // get bounding box
1020
+ dict->lookup("BBox", &obj1);
1021
+ if (!obj1.isArray()) {
1022
+ obj1.free();
1023
+ error(getPos(), "Bad form bounding box");
1024
+ return;
1025
+ }
1026
+ for (i = 0; i < 4; ++i) {
1027
+ obj1.arrayGet(i, &obj2);
1028
+ bbox[i] = obj2.getNum();
1029
+ obj2.free();
1030
+ }
1031
+ obj1.free();
1032
+
1033
+ // get matrix
1034
+ dict->lookup("Matrix", &obj1);
1035
+ if (obj1.isArray()) {
1036
+ for (i = 0; i < 6; ++i) {
1037
+ obj1.arrayGet(i, &obj2);
1038
+ m[i] = obj2.getNum();
1039
+ obj2.free();
1040
+ }
1041
+ } else {
1042
+ m[0] = 1; m[1] = 0;
1043
+ m[2] = 0; m[3] = 1;
1044
+ m[4] = 0; m[5] = 0;
1045
+ }
1046
+ obj1.free();
1047
+
1048
+ // get resources
1049
+ dict->lookup("Resources", &obj1);
1050
+ resDict = obj1.isDict() ? obj1.getDict() : (Dict *)NULL;
1051
+
1052
+ // draw it
1053
+ ++formDepth;
1054
+ doForm1(str, resDict, m, bbox, gTrue, gTrue,
1055
+ blendingColorSpace, isolated, knockout,
1056
+ alpha, transferFunc, backdropColor);
1057
+ --formDepth;
1058
+
1059
+ if (blendingColorSpace) {
1060
+ delete blendingColorSpace;
1061
+ }
1062
+ obj1.free();
1063
+ }
1064
+
1065
+ void Gfx::opSetRenderingIntent(Object args[], int numArgs) {
1066
+ }
1067
+
1068
+ //------------------------------------------------------------------------
1069
+ // color operators
1070
+ //------------------------------------------------------------------------
1071
+
1072
+ void Gfx::opSetFillGray(Object args[], int numArgs) {
1073
+ GfxColor color;
1074
+
1075
+ state->setFillPattern(NULL);
1076
+ state->setFillColorSpace(new GfxDeviceGrayColorSpace());
1077
+ out->updateFillColorSpace(state);
1078
+ color.c[0] = dblToCol(args[0].getNum());
1079
+ state->setFillColor(&color);
1080
+ out->updateFillColor(state);
1081
+ }
1082
+
1083
+ void Gfx::opSetStrokeGray(Object args[], int numArgs) {
1084
+ GfxColor color;
1085
+
1086
+ state->setStrokePattern(NULL);
1087
+ state->setStrokeColorSpace(new GfxDeviceGrayColorSpace());
1088
+ out->updateStrokeColorSpace(state);
1089
+ color.c[0] = dblToCol(args[0].getNum());
1090
+ state->setStrokeColor(&color);
1091
+ out->updateStrokeColor(state);
1092
+ }
1093
+
1094
+ void Gfx::opSetFillCMYKColor(Object args[], int numArgs) {
1095
+ GfxColor color;
1096
+ int i;
1097
+
1098
+ state->setFillPattern(NULL);
1099
+ state->setFillColorSpace(new GfxDeviceCMYKColorSpace());
1100
+ out->updateFillColorSpace(state);
1101
+ for (i = 0; i < 4; ++i) {
1102
+ color.c[i] = dblToCol(args[i].getNum());
1103
+ }
1104
+ state->setFillColor(&color);
1105
+ out->updateFillColor(state);
1106
+ }
1107
+
1108
+ void Gfx::opSetStrokeCMYKColor(Object args[], int numArgs) {
1109
+ GfxColor color;
1110
+ int i;
1111
+
1112
+ state->setStrokePattern(NULL);
1113
+ state->setStrokeColorSpace(new GfxDeviceCMYKColorSpace());
1114
+ out->updateStrokeColorSpace(state);
1115
+ for (i = 0; i < 4; ++i) {
1116
+ color.c[i] = dblToCol(args[i].getNum());
1117
+ }
1118
+ state->setStrokeColor(&color);
1119
+ out->updateStrokeColor(state);
1120
+ }
1121
+
1122
+ void Gfx::opSetFillRGBColor(Object args[], int numArgs) {
1123
+ GfxColor color;
1124
+ int i;
1125
+
1126
+ state->setFillPattern(NULL);
1127
+ state->setFillColorSpace(new GfxDeviceRGBColorSpace());
1128
+ out->updateFillColorSpace(state);
1129
+ for (i = 0; i < 3; ++i) {
1130
+ color.c[i] = dblToCol(args[i].getNum());
1131
+ }
1132
+ state->setFillColor(&color);
1133
+ out->updateFillColor(state);
1134
+ }
1135
+
1136
+ void Gfx::opSetStrokeRGBColor(Object args[], int numArgs) {
1137
+ GfxColor color;
1138
+ int i;
1139
+
1140
+ state->setStrokePattern(NULL);
1141
+ state->setStrokeColorSpace(new GfxDeviceRGBColorSpace());
1142
+ out->updateStrokeColorSpace(state);
1143
+ for (i = 0; i < 3; ++i) {
1144
+ color.c[i] = dblToCol(args[i].getNum());
1145
+ }
1146
+ state->setStrokeColor(&color);
1147
+ out->updateStrokeColor(state);
1148
+ }
1149
+
1150
+ void Gfx::opSetFillColorSpace(Object args[], int numArgs) {
1151
+ Object obj;
1152
+ GfxColorSpace *colorSpace;
1153
+ GfxColor color;
1154
+
1155
+ state->setFillPattern(NULL);
1156
+ res->lookupColorSpace(args[0].getName(), &obj);
1157
+ if (obj.isNull()) {
1158
+ colorSpace = GfxColorSpace::parse(&args[0]);
1159
+ } else {
1160
+ colorSpace = GfxColorSpace::parse(&obj);
1161
+ }
1162
+ obj.free();
1163
+ if (colorSpace) {
1164
+ state->setFillColorSpace(colorSpace);
1165
+ out->updateFillColorSpace(state);
1166
+ colorSpace->getDefaultColor(&color);
1167
+ state->setFillColor(&color);
1168
+ out->updateFillColor(state);
1169
+ } else {
1170
+ error(getPos(), "Bad color space (fill)");
1171
+ }
1172
+ }
1173
+
1174
+ void Gfx::opSetStrokeColorSpace(Object args[], int numArgs) {
1175
+ Object obj;
1176
+ GfxColorSpace *colorSpace;
1177
+ GfxColor color;
1178
+
1179
+ state->setStrokePattern(NULL);
1180
+ res->lookupColorSpace(args[0].getName(), &obj);
1181
+ if (obj.isNull()) {
1182
+ colorSpace = GfxColorSpace::parse(&args[0]);
1183
+ } else {
1184
+ colorSpace = GfxColorSpace::parse(&obj);
1185
+ }
1186
+ obj.free();
1187
+ if (colorSpace) {
1188
+ state->setStrokeColorSpace(colorSpace);
1189
+ out->updateStrokeColorSpace(state);
1190
+ colorSpace->getDefaultColor(&color);
1191
+ state->setStrokeColor(&color);
1192
+ out->updateStrokeColor(state);
1193
+ } else {
1194
+ error(getPos(), "Bad color space (stroke)");
1195
+ }
1196
+ }
1197
+
1198
+ void Gfx::opSetFillColor(Object args[], int numArgs) {
1199
+ GfxColor color;
1200
+ int i;
1201
+
1202
+ if (numArgs != state->getFillColorSpace()->getNComps()) {
1203
+ error(getPos(), "Incorrect number of arguments in 'sc' command");
1204
+ return;
1205
+ }
1206
+ state->setFillPattern(NULL);
1207
+ for (i = 0; i < numArgs; ++i) {
1208
+ color.c[i] = dblToCol(args[i].getNum());
1209
+ }
1210
+ state->setFillColor(&color);
1211
+ out->updateFillColor(state);
1212
+ }
1213
+
1214
+ void Gfx::opSetStrokeColor(Object args[], int numArgs) {
1215
+ GfxColor color;
1216
+ int i;
1217
+
1218
+ if (numArgs != state->getStrokeColorSpace()->getNComps()) {
1219
+ error(getPos(), "Incorrect number of arguments in 'SC' command");
1220
+ return;
1221
+ }
1222
+ state->setStrokePattern(NULL);
1223
+ for (i = 0; i < numArgs; ++i) {
1224
+ color.c[i] = dblToCol(args[i].getNum());
1225
+ }
1226
+ state->setStrokeColor(&color);
1227
+ out->updateStrokeColor(state);
1228
+ }
1229
+
1230
+ void Gfx::opSetFillColorN(Object args[], int numArgs) {
1231
+ GfxColor color;
1232
+ GfxPattern *pattern;
1233
+ int i;
1234
+
1235
+ if (state->getFillColorSpace()->getMode() == csPattern) {
1236
+ if (numArgs > 1) {
1237
+ if (!((GfxPatternColorSpace *)state->getFillColorSpace())->getUnder() ||
1238
+ numArgs - 1 != ((GfxPatternColorSpace *)state->getFillColorSpace())
1239
+ ->getUnder()->getNComps()) {
1240
+ error(getPos(), "Incorrect number of arguments in 'scn' command");
1241
+ return;
1242
+ }
1243
+ for (i = 0; i < numArgs - 1 && i < gfxColorMaxComps; ++i) {
1244
+ if (args[i].isNum()) {
1245
+ color.c[i] = dblToCol(args[i].getNum());
1246
+ }
1247
+ }
1248
+ state->setFillColor(&color);
1249
+ out->updateFillColor(state);
1250
+ }
1251
+ if (args[numArgs-1].isName() &&
1252
+ (pattern = res->lookupPattern(args[numArgs-1].getName()))) {
1253
+ state->setFillPattern(pattern);
1254
+ }
1255
+
1256
+ } else {
1257
+ if (numArgs != state->getFillColorSpace()->getNComps()) {
1258
+ error(getPos(), "Incorrect number of arguments in 'scn' command");
1259
+ return;
1260
+ }
1261
+ state->setFillPattern(NULL);
1262
+ for (i = 0; i < numArgs && i < gfxColorMaxComps; ++i) {
1263
+ if (args[i].isNum()) {
1264
+ color.c[i] = dblToCol(args[i].getNum());
1265
+ }
1266
+ }
1267
+ state->setFillColor(&color);
1268
+ out->updateFillColor(state);
1269
+ }
1270
+ }
1271
+
1272
+ void Gfx::opSetStrokeColorN(Object args[], int numArgs) {
1273
+ GfxColor color;
1274
+ GfxPattern *pattern;
1275
+ int i;
1276
+
1277
+ if (state->getStrokeColorSpace()->getMode() == csPattern) {
1278
+ if (numArgs > 1) {
1279
+ if (!((GfxPatternColorSpace *)state->getStrokeColorSpace())
1280
+ ->getUnder() ||
1281
+ numArgs - 1 != ((GfxPatternColorSpace *)state->getStrokeColorSpace())
1282
+ ->getUnder()->getNComps()) {
1283
+ error(getPos(), "Incorrect number of arguments in 'SCN' command");
1284
+ return;
1285
+ }
1286
+ for (i = 0; i < numArgs - 1 && i < gfxColorMaxComps; ++i) {
1287
+ if (args[i].isNum()) {
1288
+ color.c[i] = dblToCol(args[i].getNum());
1289
+ }
1290
+ }
1291
+ state->setStrokeColor(&color);
1292
+ out->updateStrokeColor(state);
1293
+ }
1294
+ if (args[numArgs-1].isName() &&
1295
+ (pattern = res->lookupPattern(args[numArgs-1].getName()))) {
1296
+ state->setStrokePattern(pattern);
1297
+ }
1298
+
1299
+ } else {
1300
+ if (numArgs != state->getStrokeColorSpace()->getNComps()) {
1301
+ error(getPos(), "Incorrect number of arguments in 'SCN' command");
1302
+ return;
1303
+ }
1304
+ state->setStrokePattern(NULL);
1305
+ for (i = 0; i < numArgs && i < gfxColorMaxComps; ++i) {
1306
+ if (args[i].isNum()) {
1307
+ color.c[i] = dblToCol(args[i].getNum());
1308
+ }
1309
+ }
1310
+ state->setStrokeColor(&color);
1311
+ out->updateStrokeColor(state);
1312
+ }
1313
+ }
1314
+
1315
+ //------------------------------------------------------------------------
1316
+ // path segment operators
1317
+ //------------------------------------------------------------------------
1318
+
1319
+ void Gfx::opMoveTo(Object args[], int numArgs) {
1320
+ state->moveTo(args[0].getNum(), args[1].getNum());
1321
+ }
1322
+
1323
+ void Gfx::opLineTo(Object args[], int numArgs) {
1324
+ if (!state->isCurPt()) {
1325
+ error(getPos(), "No current point in lineto");
1326
+ return;
1327
+ }
1328
+ state->lineTo(args[0].getNum(), args[1].getNum());
1329
+ }
1330
+
1331
+ void Gfx::opCurveTo(Object args[], int numArgs) {
1332
+ double x1, y1, x2, y2, x3, y3;
1333
+
1334
+ if (!state->isCurPt()) {
1335
+ error(getPos(), "No current point in curveto");
1336
+ return;
1337
+ }
1338
+ x1 = args[0].getNum();
1339
+ y1 = args[1].getNum();
1340
+ x2 = args[2].getNum();
1341
+ y2 = args[3].getNum();
1342
+ x3 = args[4].getNum();
1343
+ y3 = args[5].getNum();
1344
+ state->curveTo(x1, y1, x2, y2, x3, y3);
1345
+ }
1346
+
1347
+ void Gfx::opCurveTo1(Object args[], int numArgs) {
1348
+ double x1, y1, x2, y2, x3, y3;
1349
+
1350
+ if (!state->isCurPt()) {
1351
+ error(getPos(), "No current point in curveto1");
1352
+ return;
1353
+ }
1354
+ x1 = state->getCurX();
1355
+ y1 = state->getCurY();
1356
+ x2 = args[0].getNum();
1357
+ y2 = args[1].getNum();
1358
+ x3 = args[2].getNum();
1359
+ y3 = args[3].getNum();
1360
+ state->curveTo(x1, y1, x2, y2, x3, y3);
1361
+ }
1362
+
1363
+ void Gfx::opCurveTo2(Object args[], int numArgs) {
1364
+ double x1, y1, x2, y2, x3, y3;
1365
+
1366
+ if (!state->isCurPt()) {
1367
+ error(getPos(), "No current point in curveto2");
1368
+ return;
1369
+ }
1370
+ x1 = args[0].getNum();
1371
+ y1 = args[1].getNum();
1372
+ x2 = args[2].getNum();
1373
+ y2 = args[3].getNum();
1374
+ x3 = x2;
1375
+ y3 = y2;
1376
+ state->curveTo(x1, y1, x2, y2, x3, y3);
1377
+ }
1378
+
1379
+ void Gfx::opRectangle(Object args[], int numArgs) {
1380
+ double x, y, w, h;
1381
+
1382
+ x = args[0].getNum();
1383
+ y = args[1].getNum();
1384
+ w = args[2].getNum();
1385
+ h = args[3].getNum();
1386
+ state->moveTo(x, y);
1387
+ state->lineTo(x + w, y);
1388
+ state->lineTo(x + w, y + h);
1389
+ state->lineTo(x, y + h);
1390
+ state->closePath();
1391
+ }
1392
+
1393
+ void Gfx::opClosePath(Object args[], int numArgs) {
1394
+ if (!state->isCurPt()) {
1395
+ error(getPos(), "No current point in closepath");
1396
+ return;
1397
+ }
1398
+ state->closePath();
1399
+ }
1400
+
1401
+ //------------------------------------------------------------------------
1402
+ // path painting operators
1403
+ //------------------------------------------------------------------------
1404
+
1405
+ void Gfx::opEndPath(Object args[], int numArgs) {
1406
+ doEndPath();
1407
+ }
1408
+
1409
+ void Gfx::opStroke(Object args[], int numArgs) {
1410
+ if (!state->isCurPt()) {
1411
+ //error(getPos(), "No path in stroke");
1412
+ return;
1413
+ }
1414
+ if (state->isPath()) {
1415
+ if (state->getStrokeColorSpace()->getMode() == csPattern) {
1416
+ doPatternStroke();
1417
+ } else {
1418
+ out->stroke(state);
1419
+ }
1420
+ }
1421
+ doEndPath();
1422
+ }
1423
+
1424
+ void Gfx::opCloseStroke(Object args[], int numArgs) {
1425
+ if (!state->isCurPt()) {
1426
+ //error(getPos(), "No path in closepath/stroke");
1427
+ return;
1428
+ }
1429
+ if (state->isPath()) {
1430
+ state->closePath();
1431
+ if (state->getStrokeColorSpace()->getMode() == csPattern) {
1432
+ doPatternStroke();
1433
+ } else {
1434
+ out->stroke(state);
1435
+ }
1436
+ }
1437
+ doEndPath();
1438
+ }
1439
+
1440
+ void Gfx::opFill(Object args[], int numArgs) {
1441
+ if (!state->isCurPt()) {
1442
+ //error(getPos(), "No path in fill");
1443
+ return;
1444
+ }
1445
+ if (state->isPath()) {
1446
+ if (state->getFillColorSpace()->getMode() == csPattern) {
1447
+ doPatternFill(gFalse);
1448
+ } else {
1449
+ out->fill(state);
1450
+ }
1451
+ }
1452
+ doEndPath();
1453
+ }
1454
+
1455
+ void Gfx::opEOFill(Object args[], int numArgs) {
1456
+ if (!state->isCurPt()) {
1457
+ //error(getPos(), "No path in eofill");
1458
+ return;
1459
+ }
1460
+ if (state->isPath()) {
1461
+ if (state->getFillColorSpace()->getMode() == csPattern) {
1462
+ doPatternFill(gTrue);
1463
+ } else {
1464
+ out->eoFill(state);
1465
+ }
1466
+ }
1467
+ doEndPath();
1468
+ }
1469
+
1470
+ void Gfx::opFillStroke(Object args[], int numArgs) {
1471
+ if (!state->isCurPt()) {
1472
+ //error(getPos(), "No path in fill/stroke");
1473
+ return;
1474
+ }
1475
+ if (state->isPath()) {
1476
+ if (state->getFillColorSpace()->getMode() == csPattern) {
1477
+ doPatternFill(gFalse);
1478
+ } else {
1479
+ out->fill(state);
1480
+ }
1481
+ if (state->getStrokeColorSpace()->getMode() == csPattern) {
1482
+ doPatternStroke();
1483
+ } else {
1484
+ out->stroke(state);
1485
+ }
1486
+ }
1487
+ doEndPath();
1488
+ }
1489
+
1490
+ void Gfx::opCloseFillStroke(Object args[], int numArgs) {
1491
+ if (!state->isCurPt()) {
1492
+ //error(getPos(), "No path in closepath/fill/stroke");
1493
+ return;
1494
+ }
1495
+ if (state->isPath()) {
1496
+ state->closePath();
1497
+ if (state->getFillColorSpace()->getMode() == csPattern) {
1498
+ doPatternFill(gFalse);
1499
+ } else {
1500
+ out->fill(state);
1501
+ }
1502
+ if (state->getStrokeColorSpace()->getMode() == csPattern) {
1503
+ doPatternStroke();
1504
+ } else {
1505
+ out->stroke(state);
1506
+ }
1507
+ }
1508
+ doEndPath();
1509
+ }
1510
+
1511
+ void Gfx::opEOFillStroke(Object args[], int numArgs) {
1512
+ if (!state->isCurPt()) {
1513
+ //error(getPos(), "No path in eofill/stroke");
1514
+ return;
1515
+ }
1516
+ if (state->isPath()) {
1517
+ if (state->getFillColorSpace()->getMode() == csPattern) {
1518
+ doPatternFill(gTrue);
1519
+ } else {
1520
+ out->eoFill(state);
1521
+ }
1522
+ if (state->getStrokeColorSpace()->getMode() == csPattern) {
1523
+ doPatternStroke();
1524
+ } else {
1525
+ out->stroke(state);
1526
+ }
1527
+ }
1528
+ doEndPath();
1529
+ }
1530
+
1531
+ void Gfx::opCloseEOFillStroke(Object args[], int numArgs) {
1532
+ if (!state->isCurPt()) {
1533
+ //error(getPos(), "No path in closepath/eofill/stroke");
1534
+ return;
1535
+ }
1536
+ if (state->isPath()) {
1537
+ state->closePath();
1538
+ if (state->getFillColorSpace()->getMode() == csPattern) {
1539
+ doPatternFill(gTrue);
1540
+ } else {
1541
+ out->eoFill(state);
1542
+ }
1543
+ if (state->getStrokeColorSpace()->getMode() == csPattern) {
1544
+ doPatternStroke();
1545
+ } else {
1546
+ out->stroke(state);
1547
+ }
1548
+ }
1549
+ doEndPath();
1550
+ }
1551
+
1552
+ void Gfx::doPatternFill(GBool eoFill) {
1553
+ GfxPattern *pattern;
1554
+
1555
+ // this is a bit of a kludge -- patterns can be really slow, so we
1556
+ // skip them if we're only doing text extraction, since they almost
1557
+ // certainly don't contain any text
1558
+ if (!out->needNonText()) {
1559
+ return;
1560
+ }
1561
+
1562
+ if (!(pattern = state->getFillPattern())) {
1563
+ return;
1564
+ }
1565
+ switch (pattern->getType()) {
1566
+ case 1:
1567
+ doTilingPatternFill((GfxTilingPattern *)pattern, gFalse, eoFill);
1568
+ break;
1569
+ case 2:
1570
+ doShadingPatternFill((GfxShadingPattern *)pattern, gFalse, eoFill);
1571
+ break;
1572
+ default:
1573
+ error(getPos(), "Unimplemented pattern type (%d) in fill",
1574
+ pattern->getType());
1575
+ break;
1576
+ }
1577
+ }
1578
+
1579
+ void Gfx::doPatternStroke() {
1580
+ GfxPattern *pattern;
1581
+
1582
+ // this is a bit of a kludge -- patterns can be really slow, so we
1583
+ // skip them if we're only doing text extraction, since they almost
1584
+ // certainly don't contain any text
1585
+ if (!out->needNonText()) {
1586
+ return;
1587
+ }
1588
+
1589
+ if (!(pattern = state->getStrokePattern())) {
1590
+ return;
1591
+ }
1592
+ switch (pattern->getType()) {
1593
+ case 1:
1594
+ doTilingPatternFill((GfxTilingPattern *)pattern, gTrue, gFalse);
1595
+ break;
1596
+ case 2:
1597
+ doShadingPatternFill((GfxShadingPattern *)pattern, gTrue, gFalse);
1598
+ break;
1599
+ default:
1600
+ error(getPos(), "Unimplemented pattern type (%d) in stroke",
1601
+ pattern->getType());
1602
+ break;
1603
+ }
1604
+ }
1605
+
1606
+ void Gfx::doTilingPatternFill(GfxTilingPattern *tPat,
1607
+ GBool stroke, GBool eoFill) {
1608
+ GfxPatternColorSpace *patCS;
1609
+ GfxColorSpace *cs;
1610
+ GfxPath *savedPath;
1611
+ double xMin, yMin, xMax, yMax, x, y, x1, y1;
1612
+ double cxMin, cyMin, cxMax, cyMax;
1613
+ int xi0, yi0, xi1, yi1, xi, yi;
1614
+ double *ctm, *btm, *ptm;
1615
+ double m[6], ictm[6], m1[6], imb[6];
1616
+ double det;
1617
+ double xstep, ystep;
1618
+ int i;
1619
+
1620
+ // get color space
1621
+ patCS = (GfxPatternColorSpace *)(stroke ? state->getStrokeColorSpace()
1622
+ : state->getFillColorSpace());
1623
+
1624
+ // construct a (pattern space) -> (current space) transform matrix
1625
+ ctm = state->getCTM();
1626
+ btm = baseMatrix;
1627
+ ptm = tPat->getMatrix();
1628
+ // iCTM = invert CTM
1629
+ det = 1 / (ctm[0] * ctm[3] - ctm[1] * ctm[2]);
1630
+ ictm[0] = ctm[3] * det;
1631
+ ictm[1] = -ctm[1] * det;
1632
+ ictm[2] = -ctm[2] * det;
1633
+ ictm[3] = ctm[0] * det;
1634
+ ictm[4] = (ctm[2] * ctm[5] - ctm[3] * ctm[4]) * det;
1635
+ ictm[5] = (ctm[1] * ctm[4] - ctm[0] * ctm[5]) * det;
1636
+ // m1 = PTM * BTM = PTM * base transform matrix
1637
+ m1[0] = ptm[0] * btm[0] + ptm[1] * btm[2];
1638
+ m1[1] = ptm[0] * btm[1] + ptm[1] * btm[3];
1639
+ m1[2] = ptm[2] * btm[0] + ptm[3] * btm[2];
1640
+ m1[3] = ptm[2] * btm[1] + ptm[3] * btm[3];
1641
+ m1[4] = ptm[4] * btm[0] + ptm[5] * btm[2] + btm[4];
1642
+ m1[5] = ptm[4] * btm[1] + ptm[5] * btm[3] + btm[5];
1643
+ // m = m1 * iCTM = (PTM * BTM) * (iCTM)
1644
+ m[0] = m1[0] * ictm[0] + m1[1] * ictm[2];
1645
+ m[1] = m1[0] * ictm[1] + m1[1] * ictm[3];
1646
+ m[2] = m1[2] * ictm[0] + m1[3] * ictm[2];
1647
+ m[3] = m1[2] * ictm[1] + m1[3] * ictm[3];
1648
+ m[4] = m1[4] * ictm[0] + m1[5] * ictm[2] + ictm[4];
1649
+ m[5] = m1[4] * ictm[1] + m1[5] * ictm[3] + ictm[5];
1650
+
1651
+ // construct a (device space) -> (pattern space) transform matrix
1652
+ det = 1 / (m1[0] * m1[3] - m1[1] * m1[2]);
1653
+ imb[0] = m1[3] * det;
1654
+ imb[1] = -m1[1] * det;
1655
+ imb[2] = -m1[2] * det;
1656
+ imb[3] = m1[0] * det;
1657
+ imb[4] = (m1[2] * m1[5] - m1[3] * m1[4]) * det;
1658
+ imb[5] = (m1[1] * m1[4] - m1[0] * m1[5]) * det;
1659
+
1660
+ // save current graphics state
1661
+ savedPath = state->getPath()->copy();
1662
+ saveState();
1663
+
1664
+ // set underlying color space (for uncolored tiling patterns); set
1665
+ // various other parameters (stroke color, line width) to match
1666
+ // Adobe's behavior
1667
+ if (tPat->getPaintType() == 2 && (cs = patCS->getUnder())) {
1668
+ state->setFillColorSpace(cs->copy());
1669
+ out->updateFillColorSpace(state);
1670
+ state->setStrokeColorSpace(cs->copy());
1671
+ out->updateStrokeColorSpace(state);
1672
+ state->setStrokeColor(state->getFillColor());
1673
+ } else {
1674
+ state->setFillColorSpace(new GfxDeviceGrayColorSpace());
1675
+ out->updateFillColorSpace(state);
1676
+ state->setStrokeColorSpace(new GfxDeviceGrayColorSpace());
1677
+ out->updateStrokeColorSpace(state);
1678
+ }
1679
+ state->setFillPattern(NULL);
1680
+ out->updateFillColor(state);
1681
+ state->setStrokePattern(NULL);
1682
+ out->updateStrokeColor(state);
1683
+ if (!stroke) {
1684
+ state->setLineWidth(0);
1685
+ out->updateLineWidth(state);
1686
+ }
1687
+
1688
+ // clip to current path
1689
+ if (stroke) {
1690
+ state->clipToStrokePath();
1691
+ out->clipToStrokePath(state);
1692
+ } else {
1693
+ state->clip();
1694
+ if (eoFill) {
1695
+ out->eoClip(state);
1696
+ } else {
1697
+ out->clip(state);
1698
+ }
1699
+ }
1700
+ state->clearPath();
1701
+
1702
+ // get the clip region, check for empty
1703
+ state->getClipBBox(&cxMin, &cyMin, &cxMax, &cyMax);
1704
+ if (cxMin > cxMax || cyMin > cyMax) {
1705
+ goto err;
1706
+ }
1707
+
1708
+ // transform clip region bbox to pattern space
1709
+ xMin = xMax = cxMin * imb[0] + cyMin * imb[2] + imb[4];
1710
+ yMin = yMax = cxMin * imb[1] + cyMin * imb[3] + imb[5];
1711
+ x1 = cxMin * imb[0] + cyMax * imb[2] + imb[4];
1712
+ y1 = cxMin * imb[1] + cyMax * imb[3] + imb[5];
1713
+ if (x1 < xMin) {
1714
+ xMin = x1;
1715
+ } else if (x1 > xMax) {
1716
+ xMax = x1;
1717
+ }
1718
+ if (y1 < yMin) {
1719
+ yMin = y1;
1720
+ } else if (y1 > yMax) {
1721
+ yMax = y1;
1722
+ }
1723
+ x1 = cxMax * imb[0] + cyMin * imb[2] + imb[4];
1724
+ y1 = cxMax * imb[1] + cyMin * imb[3] + imb[5];
1725
+ if (x1 < xMin) {
1726
+ xMin = x1;
1727
+ } else if (x1 > xMax) {
1728
+ xMax = x1;
1729
+ }
1730
+ if (y1 < yMin) {
1731
+ yMin = y1;
1732
+ } else if (y1 > yMax) {
1733
+ yMax = y1;
1734
+ }
1735
+ x1 = cxMax * imb[0] + cyMax * imb[2] + imb[4];
1736
+ y1 = cxMax * imb[1] + cyMax * imb[3] + imb[5];
1737
+ if (x1 < xMin) {
1738
+ xMin = x1;
1739
+ } else if (x1 > xMax) {
1740
+ xMax = x1;
1741
+ }
1742
+ if (y1 < yMin) {
1743
+ yMin = y1;
1744
+ } else if (y1 > yMax) {
1745
+ yMax = y1;
1746
+ }
1747
+
1748
+ // draw the pattern
1749
+ //~ this should treat negative steps differently -- start at right/top
1750
+ //~ edge instead of left/bottom (?)
1751
+ xstep = fabs(tPat->getXStep());
1752
+ ystep = fabs(tPat->getYStep());
1753
+ xi0 = (int)ceil((xMin - tPat->getBBox()[2]) / xstep);
1754
+ xi1 = (int)floor((xMax - tPat->getBBox()[0]) / xstep) + 1;
1755
+ yi0 = (int)ceil((yMin - tPat->getBBox()[3]) / ystep);
1756
+ yi1 = (int)floor((yMax - tPat->getBBox()[1]) / ystep) + 1;
1757
+ for (i = 0; i < 4; ++i) {
1758
+ m1[i] = m[i];
1759
+ }
1760
+ if (out->useTilingPatternFill()) {
1761
+ m1[4] = m[4];
1762
+ m1[5] = m[5];
1763
+ out->tilingPatternFill(state, tPat->getContentStream(),
1764
+ tPat->getPaintType(), tPat->getResDict(),
1765
+ m1, tPat->getBBox(),
1766
+ xi0, yi0, xi1, yi1, xstep, ystep);
1767
+ } else {
1768
+ for (yi = yi0; yi < yi1; ++yi) {
1769
+ for (xi = xi0; xi < xi1; ++xi) {
1770
+ x = xi * xstep;
1771
+ y = yi * ystep;
1772
+ m1[4] = x * m[0] + y * m[2] + m[4];
1773
+ m1[5] = x * m[1] + y * m[3] + m[5];
1774
+ doForm1(tPat->getContentStream(), tPat->getResDict(),
1775
+ m1, tPat->getBBox());
1776
+ }
1777
+ }
1778
+ }
1779
+
1780
+ // restore graphics state
1781
+ err:
1782
+ restoreState();
1783
+ state->setPath(savedPath);
1784
+ }
1785
+
1786
+ void Gfx::doShadingPatternFill(GfxShadingPattern *sPat,
1787
+ GBool stroke, GBool eoFill) {
1788
+ GfxShading *shading;
1789
+ GfxPath *savedPath;
1790
+ double *ctm, *btm, *ptm;
1791
+ double m[6], ictm[6], m1[6];
1792
+ double xMin, yMin, xMax, yMax;
1793
+ double det;
1794
+
1795
+ shading = sPat->getShading();
1796
+
1797
+ // save current graphics state
1798
+ savedPath = state->getPath()->copy();
1799
+ saveState();
1800
+
1801
+ // clip to bbox
1802
+ if (shading->getHasBBox()) {
1803
+ shading->getBBox(&xMin, &yMin, &xMax, &yMax);
1804
+ state->moveTo(xMin, yMin);
1805
+ state->lineTo(xMax, yMin);
1806
+ state->lineTo(xMax, yMax);
1807
+ state->lineTo(xMin, yMax);
1808
+ state->closePath();
1809
+ state->clip();
1810
+ out->clip(state);
1811
+ state->setPath(savedPath->copy());
1812
+ }
1813
+
1814
+ // clip to current path
1815
+ if (stroke) {
1816
+ state->clipToStrokePath();
1817
+ out->clipToStrokePath(state);
1818
+ } else {
1819
+ state->clip();
1820
+ if (eoFill) {
1821
+ out->eoClip(state);
1822
+ } else {
1823
+ out->clip(state);
1824
+ }
1825
+ }
1826
+
1827
+ // set the color space
1828
+ state->setFillColorSpace(shading->getColorSpace()->copy());
1829
+ out->updateFillColorSpace(state);
1830
+
1831
+ // background color fill
1832
+ if (shading->getHasBackground()) {
1833
+ state->setFillColor(shading->getBackground());
1834
+ out->updateFillColor(state);
1835
+ out->fill(state);
1836
+ }
1837
+ state->clearPath();
1838
+
1839
+ // construct a (pattern space) -> (current space) transform matrix
1840
+ ctm = state->getCTM();
1841
+ btm = baseMatrix;
1842
+ ptm = sPat->getMatrix();
1843
+ // iCTM = invert CTM
1844
+ det = 1 / (ctm[0] * ctm[3] - ctm[1] * ctm[2]);
1845
+ ictm[0] = ctm[3] * det;
1846
+ ictm[1] = -ctm[1] * det;
1847
+ ictm[2] = -ctm[2] * det;
1848
+ ictm[3] = ctm[0] * det;
1849
+ ictm[4] = (ctm[2] * ctm[5] - ctm[3] * ctm[4]) * det;
1850
+ ictm[5] = (ctm[1] * ctm[4] - ctm[0] * ctm[5]) * det;
1851
+ // m1 = PTM * BTM = PTM * base transform matrix
1852
+ m1[0] = ptm[0] * btm[0] + ptm[1] * btm[2];
1853
+ m1[1] = ptm[0] * btm[1] + ptm[1] * btm[3];
1854
+ m1[2] = ptm[2] * btm[0] + ptm[3] * btm[2];
1855
+ m1[3] = ptm[2] * btm[1] + ptm[3] * btm[3];
1856
+ m1[4] = ptm[4] * btm[0] + ptm[5] * btm[2] + btm[4];
1857
+ m1[5] = ptm[4] * btm[1] + ptm[5] * btm[3] + btm[5];
1858
+ // m = m1 * iCTM = (PTM * BTM) * (iCTM)
1859
+ m[0] = m1[0] * ictm[0] + m1[1] * ictm[2];
1860
+ m[1] = m1[0] * ictm[1] + m1[1] * ictm[3];
1861
+ m[2] = m1[2] * ictm[0] + m1[3] * ictm[2];
1862
+ m[3] = m1[2] * ictm[1] + m1[3] * ictm[3];
1863
+ m[4] = m1[4] * ictm[0] + m1[5] * ictm[2] + ictm[4];
1864
+ m[5] = m1[4] * ictm[1] + m1[5] * ictm[3] + ictm[5];
1865
+
1866
+ // set the new matrix
1867
+ state->concatCTM(m[0], m[1], m[2], m[3], m[4], m[5]);
1868
+ out->updateCTM(state, m[0], m[1], m[2], m[3], m[4], m[5]);
1869
+
1870
+ #if 1 //~tmp: turn off anti-aliasing temporarily
1871
+ GBool vaa = out->getVectorAntialias();
1872
+ if (vaa) {
1873
+ out->setVectorAntialias(gFalse);
1874
+ }
1875
+ #endif
1876
+
1877
+ // do shading type-specific operations
1878
+ switch (shading->getType()) {
1879
+ case 1:
1880
+ doFunctionShFill((GfxFunctionShading *)shading);
1881
+ break;
1882
+ case 2:
1883
+ doAxialShFill((GfxAxialShading *)shading);
1884
+ break;
1885
+ case 3:
1886
+ doRadialShFill((GfxRadialShading *)shading);
1887
+ break;
1888
+ case 4:
1889
+ case 5:
1890
+ doGouraudTriangleShFill((GfxGouraudTriangleShading *)shading);
1891
+ break;
1892
+ case 6:
1893
+ case 7:
1894
+ doPatchMeshShFill((GfxPatchMeshShading *)shading);
1895
+ break;
1896
+ }
1897
+
1898
+ #if 1 //~tmp: turn off anti-aliasing temporarily
1899
+ if (vaa) {
1900
+ out->setVectorAntialias(gTrue);
1901
+ }
1902
+ #endif
1903
+
1904
+ // restore graphics state
1905
+ restoreState();
1906
+ state->setPath(savedPath);
1907
+ }
1908
+
1909
+ void Gfx::opShFill(Object args[], int numArgs) {
1910
+ GfxShading *shading;
1911
+ GfxPath *savedPath;
1912
+ double xMin, yMin, xMax, yMax;
1913
+
1914
+ if (!(shading = res->lookupShading(args[0].getName()))) {
1915
+ return;
1916
+ }
1917
+
1918
+ // save current graphics state
1919
+ savedPath = state->getPath()->copy();
1920
+ saveState();
1921
+
1922
+ // clip to bbox
1923
+ if (shading->getHasBBox()) {
1924
+ shading->getBBox(&xMin, &yMin, &xMax, &yMax);
1925
+ state->moveTo(xMin, yMin);
1926
+ state->lineTo(xMax, yMin);
1927
+ state->lineTo(xMax, yMax);
1928
+ state->lineTo(xMin, yMax);
1929
+ state->closePath();
1930
+ state->clip();
1931
+ out->clip(state);
1932
+ state->clearPath();
1933
+ }
1934
+
1935
+ // set the color space
1936
+ state->setFillColorSpace(shading->getColorSpace()->copy());
1937
+ out->updateFillColorSpace(state);
1938
+
1939
+ #if 1 //~tmp: turn off anti-aliasing temporarily
1940
+ GBool vaa = out->getVectorAntialias();
1941
+ if (vaa) {
1942
+ out->setVectorAntialias(gFalse);
1943
+ }
1944
+ #endif
1945
+
1946
+ // do shading type-specific operations
1947
+ switch (shading->getType()) {
1948
+ case 1:
1949
+ doFunctionShFill((GfxFunctionShading *)shading);
1950
+ break;
1951
+ case 2:
1952
+ doAxialShFill((GfxAxialShading *)shading);
1953
+ break;
1954
+ case 3:
1955
+ doRadialShFill((GfxRadialShading *)shading);
1956
+ break;
1957
+ case 4:
1958
+ case 5:
1959
+ doGouraudTriangleShFill((GfxGouraudTriangleShading *)shading);
1960
+ break;
1961
+ case 6:
1962
+ case 7:
1963
+ doPatchMeshShFill((GfxPatchMeshShading *)shading);
1964
+ break;
1965
+ }
1966
+
1967
+ #if 1 //~tmp: turn off anti-aliasing temporarily
1968
+ if (vaa) {
1969
+ out->setVectorAntialias(gTrue);
1970
+ }
1971
+ #endif
1972
+
1973
+ // restore graphics state
1974
+ restoreState();
1975
+ state->setPath(savedPath);
1976
+
1977
+ delete shading;
1978
+ }
1979
+
1980
+ void Gfx::doFunctionShFill(GfxFunctionShading *shading) {
1981
+ double x0, y0, x1, y1;
1982
+ GfxColor colors[4];
1983
+
1984
+ if (out->useShadedFills() &&
1985
+ out->functionShadedFill(state, shading)) {
1986
+ return;
1987
+ }
1988
+
1989
+ shading->getDomain(&x0, &y0, &x1, &y1);
1990
+ shading->getColor(x0, y0, &colors[0]);
1991
+ shading->getColor(x0, y1, &colors[1]);
1992
+ shading->getColor(x1, y0, &colors[2]);
1993
+ shading->getColor(x1, y1, &colors[3]);
1994
+ doFunctionShFill1(shading, x0, y0, x1, y1, colors, 0);
1995
+ }
1996
+
1997
+ void Gfx::doFunctionShFill1(GfxFunctionShading *shading,
1998
+ double x0, double y0,
1999
+ double x1, double y1,
2000
+ GfxColor *colors, int depth) {
2001
+ GfxColor fillColor;
2002
+ GfxColor color0M, color1M, colorM0, colorM1, colorMM;
2003
+ GfxColor colors2[4];
2004
+ double *matrix;
2005
+ double xM, yM;
2006
+ int nComps, i, j;
2007
+
2008
+ nComps = shading->getColorSpace()->getNComps();
2009
+ matrix = shading->getMatrix();
2010
+
2011
+ // compare the four corner colors
2012
+ for (i = 0; i < 4; ++i) {
2013
+ for (j = 0; j < nComps; ++j) {
2014
+ if (abs(colors[i].c[j] - colors[(i+1)&3].c[j]) > functionColorDelta) {
2015
+ break;
2016
+ }
2017
+ }
2018
+ if (j < nComps) {
2019
+ break;
2020
+ }
2021
+ }
2022
+
2023
+ // center of the rectangle
2024
+ xM = 0.5 * (x0 + x1);
2025
+ yM = 0.5 * (y0 + y1);
2026
+
2027
+ // the four corner colors are close (or we hit the recursive limit)
2028
+ // -- fill the rectangle; but require at least one subdivision
2029
+ // (depth==0) to avoid problems when the four outer corners of the
2030
+ // shaded region are the same color
2031
+ if ((i == 4 && depth > 0) || depth == functionMaxDepth) {
2032
+
2033
+ // use the center color
2034
+ shading->getColor(xM, yM, &fillColor);
2035
+ state->setFillColor(&fillColor);
2036
+ out->updateFillColor(state);
2037
+
2038
+ // fill the rectangle
2039
+ state->moveTo(x0 * matrix[0] + y0 * matrix[2] + matrix[4],
2040
+ x0 * matrix[1] + y0 * matrix[3] + matrix[5]);
2041
+ state->lineTo(x1 * matrix[0] + y0 * matrix[2] + matrix[4],
2042
+ x1 * matrix[1] + y0 * matrix[3] + matrix[5]);
2043
+ state->lineTo(x1 * matrix[0] + y1 * matrix[2] + matrix[4],
2044
+ x1 * matrix[1] + y1 * matrix[3] + matrix[5]);
2045
+ state->lineTo(x0 * matrix[0] + y1 * matrix[2] + matrix[4],
2046
+ x0 * matrix[1] + y1 * matrix[3] + matrix[5]);
2047
+ state->closePath();
2048
+ out->fill(state);
2049
+ state->clearPath();
2050
+
2051
+ // the four corner colors are not close enough -- subdivide the
2052
+ // rectangle
2053
+ } else {
2054
+
2055
+ // colors[0] colorM0 colors[2]
2056
+ // (x0,y0) (xM,y0) (x1,y0)
2057
+ // +----------+----------+
2058
+ // | | |
2059
+ // | UL | UR |
2060
+ // color0M | colorMM | color1M
2061
+ // (x0,yM) +----------+----------+ (x1,yM)
2062
+ // | (xM,yM) |
2063
+ // | LL | LR |
2064
+ // | | |
2065
+ // +----------+----------+
2066
+ // colors[1] colorM1 colors[3]
2067
+ // (x0,y1) (xM,y1) (x1,y1)
2068
+
2069
+ shading->getColor(x0, yM, &color0M);
2070
+ shading->getColor(x1, yM, &color1M);
2071
+ shading->getColor(xM, y0, &colorM0);
2072
+ shading->getColor(xM, y1, &colorM1);
2073
+ shading->getColor(xM, yM, &colorMM);
2074
+
2075
+ // upper-left sub-rectangle
2076
+ colors2[0] = colors[0];
2077
+ colors2[1] = color0M;
2078
+ colors2[2] = colorM0;
2079
+ colors2[3] = colorMM;
2080
+ doFunctionShFill1(shading, x0, y0, xM, yM, colors2, depth + 1);
2081
+
2082
+ // lower-left sub-rectangle
2083
+ colors2[0] = color0M;
2084
+ colors2[1] = colors[1];
2085
+ colors2[2] = colorMM;
2086
+ colors2[3] = colorM1;
2087
+ doFunctionShFill1(shading, x0, yM, xM, y1, colors2, depth + 1);
2088
+
2089
+ // upper-right sub-rectangle
2090
+ colors2[0] = colorM0;
2091
+ colors2[1] = colorMM;
2092
+ colors2[2] = colors[2];
2093
+ colors2[3] = color1M;
2094
+ doFunctionShFill1(shading, xM, y0, x1, yM, colors2, depth + 1);
2095
+
2096
+ // lower-right sub-rectangle
2097
+ colors2[0] = colorMM;
2098
+ colors2[1] = colorM1;
2099
+ colors2[2] = color1M;
2100
+ colors2[3] = colors[3];
2101
+ doFunctionShFill1(shading, xM, yM, x1, y1, colors2, depth + 1);
2102
+ }
2103
+ }
2104
+
2105
+ void Gfx::doAxialShFill(GfxAxialShading *shading) {
2106
+ double xMin, yMin, xMax, yMax;
2107
+ double x0, y0, x1, y1;
2108
+ double dx, dy, mul;
2109
+ GBool dxZero, dyZero;
2110
+ double tMin, tMax, t, tx, ty;
2111
+ double s[4], sMin, sMax, tmp;
2112
+ double ux0, uy0, ux1, uy1, vx0, vy0, vx1, vy1;
2113
+ double t0, t1, tt;
2114
+ double ta[axialMaxSplits + 1];
2115
+ int next[axialMaxSplits + 1];
2116
+ GfxColor color0, color1;
2117
+ int nComps;
2118
+ int i, j, k, kk;
2119
+
2120
+ if (out->useShadedFills() &&
2121
+ out->axialShadedFill(state, shading)) {
2122
+ return;
2123
+ }
2124
+
2125
+ // get the clip region bbox
2126
+ state->getUserClipBBox(&xMin, &yMin, &xMax, &yMax);
2127
+
2128
+ // compute min and max t values, based on the four corners of the
2129
+ // clip region bbox
2130
+ shading->getCoords(&x0, &y0, &x1, &y1);
2131
+ dx = x1 - x0;
2132
+ dy = y1 - y0;
2133
+ dxZero = fabs(dx) < 0.01;
2134
+ dyZero = fabs(dy) < 0.01;
2135
+ if (dxZero && dyZero) {
2136
+ tMin = tMax = 0;
2137
+ } else {
2138
+ mul = 1 / (dx * dx + dy * dy);
2139
+ tMin = tMax = ((xMin - x0) * dx + (yMin - y0) * dy) * mul;
2140
+ t = ((xMin - x0) * dx + (yMax - y0) * dy) * mul;
2141
+ if (t < tMin) {
2142
+ tMin = t;
2143
+ } else if (t > tMax) {
2144
+ tMax = t;
2145
+ }
2146
+ t = ((xMax - x0) * dx + (yMin - y0) * dy) * mul;
2147
+ if (t < tMin) {
2148
+ tMin = t;
2149
+ } else if (t > tMax) {
2150
+ tMax = t;
2151
+ }
2152
+ t = ((xMax - x0) * dx + (yMax - y0) * dy) * mul;
2153
+ if (t < tMin) {
2154
+ tMin = t;
2155
+ } else if (t > tMax) {
2156
+ tMax = t;
2157
+ }
2158
+ if (tMin < 0 && !shading->getExtend0()) {
2159
+ tMin = 0;
2160
+ }
2161
+ if (tMax > 1 && !shading->getExtend1()) {
2162
+ tMax = 1;
2163
+ }
2164
+ }
2165
+
2166
+ // get the function domain
2167
+ t0 = shading->getDomain0();
2168
+ t1 = shading->getDomain1();
2169
+
2170
+ // Traverse the t axis and do the shading.
2171
+ //
2172
+ // For each point (tx, ty) on the t axis, consider a line through
2173
+ // that point perpendicular to the t axis:
2174
+ //
2175
+ // x(s) = tx + s * -dy --> s = (x - tx) / -dy
2176
+ // y(s) = ty + s * dx --> s = (y - ty) / dx
2177
+ //
2178
+ // Then look at the intersection of this line with the bounding box
2179
+ // (xMin, yMin, xMax, yMax). In the general case, there are four
2180
+ // intersection points:
2181
+ //
2182
+ // s0 = (xMin - tx) / -dy
2183
+ // s1 = (xMax - tx) / -dy
2184
+ // s2 = (yMin - ty) / dx
2185
+ // s3 = (yMax - ty) / dx
2186
+ //
2187
+ // and we want the middle two s values.
2188
+ //
2189
+ // In the case where dx = 0, take s0 and s1; in the case where dy =
2190
+ // 0, take s2 and s3.
2191
+ //
2192
+ // Each filled polygon is bounded by two of these line segments
2193
+ // perpdendicular to the t axis.
2194
+ //
2195
+ // The t axis is bisected into smaller regions until the color
2196
+ // difference across a region is small enough, and then the region
2197
+ // is painted with a single color.
2198
+
2199
+ // set up: require at least one split to avoid problems when the two
2200
+ // ends of the t axis have the same color
2201
+ nComps = shading->getColorSpace()->getNComps();
2202
+ ta[0] = tMin;
2203
+ next[0] = axialMaxSplits / 2;
2204
+ ta[axialMaxSplits / 2] = 0.5 * (tMin + tMax);
2205
+ next[axialMaxSplits / 2] = axialMaxSplits;
2206
+ ta[axialMaxSplits] = tMax;
2207
+
2208
+ // compute the color at t = tMin
2209
+ if (tMin < 0) {
2210
+ tt = t0;
2211
+ } else if (tMin > 1) {
2212
+ tt = t1;
2213
+ } else {
2214
+ tt = t0 + (t1 - t0) * tMin;
2215
+ }
2216
+ shading->getColor(tt, &color0);
2217
+
2218
+ // compute the coordinates of the point on the t axis at t = tMin;
2219
+ // then compute the intersection of the perpendicular line with the
2220
+ // bounding box
2221
+ tx = x0 + tMin * dx;
2222
+ ty = y0 + tMin * dy;
2223
+ if (dxZero && dyZero) {
2224
+ sMin = sMax = 0;
2225
+ } else if (dxZero) {
2226
+ sMin = (xMin - tx) / -dy;
2227
+ sMax = (xMax - tx) / -dy;
2228
+ if (sMin > sMax) { tmp = sMin; sMin = sMax; sMax = tmp; }
2229
+ } else if (dyZero) {
2230
+ sMin = (yMin - ty) / dx;
2231
+ sMax = (yMax - ty) / dx;
2232
+ if (sMin > sMax) { tmp = sMin; sMin = sMax; sMax = tmp; }
2233
+ } else {
2234
+ s[0] = (yMin - ty) / dx;
2235
+ s[1] = (yMax - ty) / dx;
2236
+ s[2] = (xMin - tx) / -dy;
2237
+ s[3] = (xMax - tx) / -dy;
2238
+ for (j = 0; j < 3; ++j) {
2239
+ kk = j;
2240
+ for (k = j + 1; k < 4; ++k) {
2241
+ if (s[k] < s[kk]) {
2242
+ kk = k;
2243
+ }
2244
+ }
2245
+ tmp = s[j]; s[j] = s[kk]; s[kk] = tmp;
2246
+ }
2247
+ sMin = s[1];
2248
+ sMax = s[2];
2249
+ }
2250
+ ux0 = tx - sMin * dy;
2251
+ uy0 = ty + sMin * dx;
2252
+ vx0 = tx - sMax * dy;
2253
+ vy0 = ty + sMax * dx;
2254
+
2255
+ i = 0;
2256
+ while (i < axialMaxSplits) {
2257
+
2258
+ // bisect until color difference is small enough or we hit the
2259
+ // bisection limit
2260
+ j = next[i];
2261
+ while (j > i + 1) {
2262
+ if (ta[j] < 0) {
2263
+ tt = t0;
2264
+ } else if (ta[j] > 1) {
2265
+ tt = t1;
2266
+ } else {
2267
+ tt = t0 + (t1 - t0) * ta[j];
2268
+ }
2269
+ shading->getColor(tt, &color1);
2270
+ for (k = 0; k < nComps; ++k) {
2271
+ if (abs(color1.c[k] - color0.c[k]) > axialColorDelta) {
2272
+ break;
2273
+ }
2274
+ }
2275
+ if (k == nComps) {
2276
+ break;
2277
+ }
2278
+ k = (i + j) / 2;
2279
+ ta[k] = 0.5 * (ta[i] + ta[j]);
2280
+ next[i] = k;
2281
+ next[k] = j;
2282
+ j = k;
2283
+ }
2284
+
2285
+ // use the average of the colors of the two sides of the region
2286
+ for (k = 0; k < nComps; ++k) {
2287
+ color0.c[k] = (color0.c[k] + color1.c[k]) / 2;
2288
+ }
2289
+
2290
+ // compute the coordinates of the point on the t axis; then
2291
+ // compute the intersection of the perpendicular line with the
2292
+ // bounding box
2293
+ tx = x0 + ta[j] * dx;
2294
+ ty = y0 + ta[j] * dy;
2295
+ if (dxZero && dyZero) {
2296
+ sMin = sMax = 0;
2297
+ } else if (dxZero) {
2298
+ sMin = (xMin - tx) / -dy;
2299
+ sMax = (xMax - tx) / -dy;
2300
+ if (sMin > sMax) { tmp = sMin; sMin = sMax; sMax = tmp; }
2301
+ } else if (dyZero) {
2302
+ sMin = (yMin - ty) / dx;
2303
+ sMax = (yMax - ty) / dx;
2304
+ if (sMin > sMax) { tmp = sMin; sMin = sMax; sMax = tmp; }
2305
+ } else {
2306
+ s[0] = (yMin - ty) / dx;
2307
+ s[1] = (yMax - ty) / dx;
2308
+ s[2] = (xMin - tx) / -dy;
2309
+ s[3] = (xMax - tx) / -dy;
2310
+ for (j = 0; j < 3; ++j) {
2311
+ kk = j;
2312
+ for (k = j + 1; k < 4; ++k) {
2313
+ if (s[k] < s[kk]) {
2314
+ kk = k;
2315
+ }
2316
+ }
2317
+ tmp = s[j]; s[j] = s[kk]; s[kk] = tmp;
2318
+ }
2319
+ sMin = s[1];
2320
+ sMax = s[2];
2321
+ }
2322
+ ux1 = tx - sMin * dy;
2323
+ uy1 = ty + sMin * dx;
2324
+ vx1 = tx - sMax * dy;
2325
+ vy1 = ty + sMax * dx;
2326
+
2327
+ // set the color
2328
+ state->setFillColor(&color0);
2329
+ out->updateFillColor(state);
2330
+
2331
+ // fill the region
2332
+ state->moveTo(ux0, uy0);
2333
+ state->lineTo(vx0, vy0);
2334
+ state->lineTo(vx1, vy1);
2335
+ state->lineTo(ux1, uy1);
2336
+ state->closePath();
2337
+ out->fill(state);
2338
+ state->clearPath();
2339
+
2340
+ // set up for next region
2341
+ ux0 = ux1;
2342
+ uy0 = uy1;
2343
+ vx0 = vx1;
2344
+ vy0 = vy1;
2345
+ color0 = color1;
2346
+ i = next[i];
2347
+ }
2348
+ }
2349
+
2350
+ void Gfx::doRadialShFill(GfxRadialShading *shading) {
2351
+ double xMin, yMin, xMax, yMax;
2352
+ double x0, y0, r0, x1, y1, r1, t0, t1;
2353
+ int nComps;
2354
+ GfxColor colorA, colorB;
2355
+ double xa, ya, xb, yb, ra, rb;
2356
+ double ta, tb, sa, sb;
2357
+ double sz, xz, yz, sMin, sMax;
2358
+ GBool enclosed;
2359
+ int ia, ib, k, n;
2360
+ double *ctm;
2361
+ double theta, alpha, angle, t;
2362
+
2363
+ if (out->useShadedFills() &&
2364
+ out->radialShadedFill(state, shading)) {
2365
+ return;
2366
+ }
2367
+
2368
+ // get the shading info
2369
+ shading->getCoords(&x0, &y0, &r0, &x1, &y1, &r1);
2370
+ t0 = shading->getDomain0();
2371
+ t1 = shading->getDomain1();
2372
+ nComps = shading->getColorSpace()->getNComps();
2373
+
2374
+ // Compute the point at which r(s) = 0; check for the enclosed
2375
+ // circles case; and compute the angles for the tangent lines.
2376
+ if (x0 == x1 && y0 == y1) {
2377
+ enclosed = gTrue;
2378
+ theta = 0; // make gcc happy
2379
+ sz = 0; // make gcc happy
2380
+ } else if (r0 == r1) {
2381
+ enclosed = gFalse;
2382
+ theta = 0;
2383
+ sz = 0; // make gcc happy
2384
+ } else {
2385
+ sz = -r0 / (r1 - r0);
2386
+ xz = x0 + sz * (x1 - x0);
2387
+ yz = y0 + sz * (y1 - y0);
2388
+ enclosed = (xz - x0) * (xz - x0) + (yz - y0) * (yz - y0) <= r0 * r0;
2389
+ theta = asin(r0 / sqrt((x0 - xz) * (x0 - xz) + (y0 - yz) * (y0 - yz)));
2390
+ if (r0 > r1) {
2391
+ theta = -theta;
2392
+ }
2393
+ }
2394
+ if (enclosed) {
2395
+ alpha = 0;
2396
+ } else {
2397
+ alpha = atan2(y1 - y0, x1 - x0);
2398
+ }
2399
+
2400
+ // compute the (possibly extended) s range
2401
+ state->getUserClipBBox(&xMin, &yMin, &xMax, &yMax);
2402
+ if (enclosed) {
2403
+ sMin = 0;
2404
+ sMax = 1;
2405
+ } else {
2406
+ sMin = 1;
2407
+ sMax = 0;
2408
+ // solve for x(s) + r(s) = xMin
2409
+ if ((x1 + r1) - (x0 + r0) != 0) {
2410
+ sa = (xMin - (x0 + r0)) / ((x1 + r1) - (x0 + r0));
2411
+ if (sa < sMin) {
2412
+ sMin = sa;
2413
+ } else if (sa > sMax) {
2414
+ sMax = sa;
2415
+ }
2416
+ }
2417
+ // solve for x(s) - r(s) = xMax
2418
+ if ((x1 - r1) - (x0 - r0) != 0) {
2419
+ sa = (xMax - (x0 - r0)) / ((x1 - r1) - (x0 - r0));
2420
+ if (sa < sMin) {
2421
+ sMin = sa;
2422
+ } else if (sa > sMax) {
2423
+ sMax = sa;
2424
+ }
2425
+ }
2426
+ // solve for y(s) + r(s) = yMin
2427
+ if ((y1 + r1) - (y0 + r0) != 0) {
2428
+ sa = (yMin - (y0 + r0)) / ((y1 + r1) - (y0 + r0));
2429
+ if (sa < sMin) {
2430
+ sMin = sa;
2431
+ } else if (sa > sMax) {
2432
+ sMax = sa;
2433
+ }
2434
+ }
2435
+ // solve for y(s) - r(s) = yMax
2436
+ if ((y1 - r1) - (y0 - r0) != 0) {
2437
+ sa = (yMax - (y0 - r0)) / ((y1 - r1) - (y0 - r0));
2438
+ if (sa < sMin) {
2439
+ sMin = sa;
2440
+ } else if (sa > sMax) {
2441
+ sMax = sa;
2442
+ }
2443
+ }
2444
+ // check against sz
2445
+ if (r0 < r1) {
2446
+ if (sMin < sz) {
2447
+ sMin = sz;
2448
+ }
2449
+ } else if (r0 > r1) {
2450
+ if (sMax > sz) {
2451
+ sMax = sz;
2452
+ }
2453
+ }
2454
+ // check the 'extend' flags
2455
+ if (!shading->getExtend0() && sMin < 0) {
2456
+ sMin = 0;
2457
+ }
2458
+ if (!shading->getExtend1() && sMax > 1) {
2459
+ sMax = 1;
2460
+ }
2461
+ }
2462
+
2463
+ // compute the number of steps into which circles must be divided to
2464
+ // achieve a curve flatness of 0.1 pixel in device space for the
2465
+ // largest circle (note that "device space" is 72 dpi when generating
2466
+ // PostScript, hence the relatively small 0.1 pixel accuracy)
2467
+ ctm = state->getCTM();
2468
+ t = fabs(ctm[0]);
2469
+ if (fabs(ctm[1]) > t) {
2470
+ t = fabs(ctm[1]);
2471
+ }
2472
+ if (fabs(ctm[2]) > t) {
2473
+ t = fabs(ctm[2]);
2474
+ }
2475
+ if (fabs(ctm[3]) > t) {
2476
+ t = fabs(ctm[3]);
2477
+ }
2478
+ if (r0 > r1) {
2479
+ t *= r0;
2480
+ } else {
2481
+ t *= r1;
2482
+ }
2483
+ if (t < 1) {
2484
+ n = 3;
2485
+ } else {
2486
+ n = (int)(M_PI / acos(1 - 0.1 / t));
2487
+ if (n < 3) {
2488
+ n = 3;
2489
+ } else if (n > 200) {
2490
+ n = 200;
2491
+ }
2492
+ }
2493
+
2494
+ // setup for the start circle
2495
+ ia = 0;
2496
+ sa = sMin;
2497
+ ta = t0 + sa * (t1 - t0);
2498
+ xa = x0 + sa * (x1 - x0);
2499
+ ya = y0 + sa * (y1 - y0);
2500
+ ra = r0 + sa * (r1 - r0);
2501
+ if (ta < t0) {
2502
+ shading->getColor(t0, &colorA);
2503
+ } else if (ta > t1) {
2504
+ shading->getColor(t1, &colorA);
2505
+ } else {
2506
+ shading->getColor(ta, &colorA);
2507
+ }
2508
+
2509
+ // fill the circles
2510
+ while (ia < radialMaxSplits) {
2511
+
2512
+ // go as far along the t axis (toward t1) as we can, such that the
2513
+ // color difference is within the tolerance (radialColorDelta) --
2514
+ // this uses bisection (between the current value, t, and t1),
2515
+ // limited to radialMaxSplits points along the t axis; require at
2516
+ // least one split to avoid problems when the innermost and
2517
+ // outermost colors are the same
2518
+ ib = radialMaxSplits;
2519
+ sb = sMax;
2520
+ tb = t0 + sb * (t1 - t0);
2521
+ if (tb < t0) {
2522
+ shading->getColor(t0, &colorB);
2523
+ } else if (tb > t1) {
2524
+ shading->getColor(t1, &colorB);
2525
+ } else {
2526
+ shading->getColor(tb, &colorB);
2527
+ }
2528
+ while (ib - ia > 1) {
2529
+ for (k = 0; k < nComps; ++k) {
2530
+ if (abs(colorB.c[k] - colorA.c[k]) > radialColorDelta) {
2531
+ break;
2532
+ }
2533
+ }
2534
+ if (k == nComps && ib < radialMaxSplits) {
2535
+ break;
2536
+ }
2537
+ ib = (ia + ib) / 2;
2538
+ sb = sMin + ((double)ib / (double)radialMaxSplits) * (sMax - sMin);
2539
+ tb = t0 + sb * (t1 - t0);
2540
+ if (tb < t0) {
2541
+ shading->getColor(t0, &colorB);
2542
+ } else if (tb > t1) {
2543
+ shading->getColor(t1, &colorB);
2544
+ } else {
2545
+ shading->getColor(tb, &colorB);
2546
+ }
2547
+ }
2548
+
2549
+ // compute center and radius of the circle
2550
+ xb = x0 + sb * (x1 - x0);
2551
+ yb = y0 + sb * (y1 - y0);
2552
+ rb = r0 + sb * (r1 - r0);
2553
+
2554
+ // use the average of the colors at the two circles
2555
+ for (k = 0; k < nComps; ++k) {
2556
+ colorA.c[k] = (colorA.c[k] + colorB.c[k]) / 2;
2557
+ }
2558
+ state->setFillColor(&colorA);
2559
+ out->updateFillColor(state);
2560
+
2561
+ if (enclosed) {
2562
+
2563
+ // construct path for first circle (counterclockwise)
2564
+ state->moveTo(xa + ra, ya);
2565
+ for (k = 1; k < n; ++k) {
2566
+ angle = ((double)k / (double)n) * 2 * M_PI;
2567
+ state->lineTo(xa + ra * cos(angle), ya + ra * sin(angle));
2568
+ }
2569
+ state->closePath();
2570
+
2571
+ // construct and append path for second circle (clockwise)
2572
+ state->moveTo(xb + rb, yb);
2573
+ for (k = 1; k < n; ++k) {
2574
+ angle = -((double)k / (double)n) * 2 * M_PI;
2575
+ state->lineTo(xb + rb * cos(angle), yb + rb * sin(angle));
2576
+ }
2577
+ state->closePath();
2578
+
2579
+ } else {
2580
+
2581
+ // construct the first subpath (clockwise)
2582
+ state->moveTo(xa + ra * cos(alpha + theta + 0.5 * M_PI),
2583
+ ya + ra * sin(alpha + theta + 0.5 * M_PI));
2584
+ for (k = 0; k < n; ++k) {
2585
+ angle = alpha + theta + 0.5 * M_PI
2586
+ - ((double)k / (double)n) * (2 * theta + M_PI);
2587
+ state->lineTo(xb + rb * cos(angle), yb + rb * sin(angle));
2588
+ }
2589
+ for (k = 0; k < n; ++k) {
2590
+ angle = alpha - theta - 0.5 * M_PI
2591
+ + ((double)k / (double)n) * (2 * theta - M_PI);
2592
+ state->lineTo(xa + ra * cos(angle), ya + ra * sin(angle));
2593
+ }
2594
+ state->closePath();
2595
+
2596
+ // construct the second subpath (counterclockwise)
2597
+ state->moveTo(xa + ra * cos(alpha + theta + 0.5 * M_PI),
2598
+ ya + ra * sin(alpha + theta + 0.5 * M_PI));
2599
+ for (k = 0; k < n; ++k) {
2600
+ angle = alpha + theta + 0.5 * M_PI
2601
+ + ((double)k / (double)n) * (-2 * theta + M_PI);
2602
+ state->lineTo(xb + rb * cos(angle), yb + rb * sin(angle));
2603
+ }
2604
+ for (k = 0; k < n; ++k) {
2605
+ angle = alpha - theta - 0.5 * M_PI
2606
+ + ((double)k / (double)n) * (2 * theta + M_PI);
2607
+ state->lineTo(xa + ra * cos(angle), ya + ra * sin(angle));
2608
+ }
2609
+ state->closePath();
2610
+ }
2611
+
2612
+ // fill the path
2613
+ out->fill(state);
2614
+ state->clearPath();
2615
+
2616
+ // step to the next value of t
2617
+ ia = ib;
2618
+ sa = sb;
2619
+ ta = tb;
2620
+ xa = xb;
2621
+ ya = yb;
2622
+ ra = rb;
2623
+ colorA = colorB;
2624
+ }
2625
+
2626
+ if (enclosed) {
2627
+ // extend the smaller circle
2628
+ if ((shading->getExtend0() && r0 <= r1) ||
2629
+ (shading->getExtend1() && r1 < r0)) {
2630
+ if (r0 <= r1) {
2631
+ ta = t0;
2632
+ ra = r0;
2633
+ xa = x0;
2634
+ ya = y0;
2635
+ } else {
2636
+ ta = t1;
2637
+ ra = r1;
2638
+ xa = x1;
2639
+ ya = y1;
2640
+ }
2641
+ shading->getColor(ta, &colorA);
2642
+ state->setFillColor(&colorA);
2643
+ out->updateFillColor(state);
2644
+ state->moveTo(xa + ra, ya);
2645
+ for (k = 1; k < n; ++k) {
2646
+ angle = ((double)k / (double)n) * 2 * M_PI;
2647
+ state->lineTo(xa + ra * cos(angle), ya + ra * sin(angle));
2648
+ }
2649
+ state->closePath();
2650
+ out->fill(state);
2651
+ state->clearPath();
2652
+ }
2653
+
2654
+ // extend the larger circle
2655
+ if ((shading->getExtend0() && r0 > r1) ||
2656
+ (shading->getExtend1() && r1 >= r0)) {
2657
+ if (r0 > r1) {
2658
+ ta = t0;
2659
+ ra = r0;
2660
+ xa = x0;
2661
+ ya = y0;
2662
+ } else {
2663
+ ta = t1;
2664
+ ra = r1;
2665
+ xa = x1;
2666
+ ya = y1;
2667
+ }
2668
+ shading->getColor(ta, &colorA);
2669
+ state->setFillColor(&colorA);
2670
+ out->updateFillColor(state);
2671
+ state->moveTo(xMin, yMin);
2672
+ state->lineTo(xMin, yMax);
2673
+ state->lineTo(xMax, yMax);
2674
+ state->lineTo(xMax, yMin);
2675
+ state->closePath();
2676
+ state->moveTo(xa + ra, ya);
2677
+ for (k = 1; k < n; ++k) {
2678
+ angle = ((double)k / (double)n) * 2 * M_PI;
2679
+ state->lineTo(xa + ra * cos(angle), ya + ra * sin(angle));
2680
+ }
2681
+ state->closePath();
2682
+ out->fill(state);
2683
+ state->clearPath();
2684
+ }
2685
+ }
2686
+ }
2687
+
2688
+ void Gfx::doGouraudTriangleShFill(GfxGouraudTriangleShading *shading) {
2689
+ double x0, y0, x1, y1, x2, y2;
2690
+ GfxColor color0, color1, color2;
2691
+ int i;
2692
+
2693
+ for (i = 0; i < shading->getNTriangles(); ++i) {
2694
+ shading->getTriangle(i, &x0, &y0, &color0,
2695
+ &x1, &y1, &color1,
2696
+ &x2, &y2, &color2);
2697
+ gouraudFillTriangle(x0, y0, &color0, x1, y1, &color1, x2, y2, &color2,
2698
+ shading->getColorSpace()->getNComps(), 0);
2699
+ }
2700
+ }
2701
+
2702
+ void Gfx::gouraudFillTriangle(double x0, double y0, GfxColor *color0,
2703
+ double x1, double y1, GfxColor *color1,
2704
+ double x2, double y2, GfxColor *color2,
2705
+ int nComps, int depth) {
2706
+ double x01, y01, x12, y12, x20, y20;
2707
+ GfxColor color01, color12, color20;
2708
+ int i;
2709
+
2710
+ for (i = 0; i < nComps; ++i) {
2711
+ if (abs(color0->c[i] - color1->c[i]) > gouraudColorDelta ||
2712
+ abs(color1->c[i] - color2->c[i]) > gouraudColorDelta) {
2713
+ break;
2714
+ }
2715
+ }
2716
+ if (i == nComps || depth == gouraudMaxDepth) {
2717
+ state->setFillColor(color0);
2718
+ out->updateFillColor(state);
2719
+ state->moveTo(x0, y0);
2720
+ state->lineTo(x1, y1);
2721
+ state->lineTo(x2, y2);
2722
+ state->closePath();
2723
+ out->fill(state);
2724
+ state->clearPath();
2725
+ } else {
2726
+ x01 = 0.5 * (x0 + x1);
2727
+ y01 = 0.5 * (y0 + y1);
2728
+ x12 = 0.5 * (x1 + x2);
2729
+ y12 = 0.5 * (y1 + y2);
2730
+ x20 = 0.5 * (x2 + x0);
2731
+ y20 = 0.5 * (y2 + y0);
2732
+ //~ if the shading has a Function, this should interpolate on the
2733
+ //~ function parameter, not on the color components
2734
+ for (i = 0; i < nComps; ++i) {
2735
+ color01.c[i] = (color0->c[i] + color1->c[i]) / 2;
2736
+ color12.c[i] = (color1->c[i] + color2->c[i]) / 2;
2737
+ color20.c[i] = (color2->c[i] + color0->c[i]) / 2;
2738
+ }
2739
+ gouraudFillTriangle(x0, y0, color0, x01, y01, &color01,
2740
+ x20, y20, &color20, nComps, depth + 1);
2741
+ gouraudFillTriangle(x01, y01, &color01, x1, y1, color1,
2742
+ x12, y12, &color12, nComps, depth + 1);
2743
+ gouraudFillTriangle(x01, y01, &color01, x12, y12, &color12,
2744
+ x20, y20, &color20, nComps, depth + 1);
2745
+ gouraudFillTriangle(x20, y20, &color20, x12, y12, &color12,
2746
+ x2, y2, color2, nComps, depth + 1);
2747
+ }
2748
+ }
2749
+
2750
+ void Gfx::doPatchMeshShFill(GfxPatchMeshShading *shading) {
2751
+ int start, i;
2752
+
2753
+ if (shading->getNPatches() > 128) {
2754
+ start = 3;
2755
+ } else if (shading->getNPatches() > 64) {
2756
+ start = 2;
2757
+ } else if (shading->getNPatches() > 16) {
2758
+ start = 1;
2759
+ } else {
2760
+ start = 0;
2761
+ }
2762
+ for (i = 0; i < shading->getNPatches(); ++i) {
2763
+ fillPatch(shading->getPatch(i), shading->getColorSpace()->getNComps(),
2764
+ start);
2765
+ }
2766
+ }
2767
+
2768
+ void Gfx::fillPatch(GfxPatch *patch, int nComps, int depth) {
2769
+ GfxPatch patch00, patch01, patch10, patch11;
2770
+ double xx[4][8], yy[4][8];
2771
+ double xxm, yym;
2772
+ int i;
2773
+
2774
+ for (i = 0; i < nComps; ++i) {
2775
+ if (abs(patch->color[0][0].c[i] - patch->color[0][1].c[i])
2776
+ > patchColorDelta ||
2777
+ abs(patch->color[0][1].c[i] - patch->color[1][1].c[i])
2778
+ > patchColorDelta ||
2779
+ abs(patch->color[1][1].c[i] - patch->color[1][0].c[i])
2780
+ > patchColorDelta ||
2781
+ abs(patch->color[1][0].c[i] - patch->color[0][0].c[i])
2782
+ > patchColorDelta) {
2783
+ break;
2784
+ }
2785
+ }
2786
+ if (i == nComps || depth == patchMaxDepth) {
2787
+ state->setFillColor(&patch->color[0][0]);
2788
+ out->updateFillColor(state);
2789
+ state->moveTo(patch->x[0][0], patch->y[0][0]);
2790
+ state->curveTo(patch->x[0][1], patch->y[0][1],
2791
+ patch->x[0][2], patch->y[0][2],
2792
+ patch->x[0][3], patch->y[0][3]);
2793
+ state->curveTo(patch->x[1][3], patch->y[1][3],
2794
+ patch->x[2][3], patch->y[2][3],
2795
+ patch->x[3][3], patch->y[3][3]);
2796
+ state->curveTo(patch->x[3][2], patch->y[3][2],
2797
+ patch->x[3][1], patch->y[3][1],
2798
+ patch->x[3][0], patch->y[3][0]);
2799
+ state->curveTo(patch->x[2][0], patch->y[2][0],
2800
+ patch->x[1][0], patch->y[1][0],
2801
+ patch->x[0][0], patch->y[0][0]);
2802
+ state->closePath();
2803
+ out->fill(state);
2804
+ state->clearPath();
2805
+ } else {
2806
+ for (i = 0; i < 4; ++i) {
2807
+ xx[i][0] = patch->x[i][0];
2808
+ yy[i][0] = patch->y[i][0];
2809
+ xx[i][1] = 0.5 * (patch->x[i][0] + patch->x[i][1]);
2810
+ yy[i][1] = 0.5 * (patch->y[i][0] + patch->y[i][1]);
2811
+ xxm = 0.5 * (patch->x[i][1] + patch->x[i][2]);
2812
+ yym = 0.5 * (patch->y[i][1] + patch->y[i][2]);
2813
+ xx[i][6] = 0.5 * (patch->x[i][2] + patch->x[i][3]);
2814
+ yy[i][6] = 0.5 * (patch->y[i][2] + patch->y[i][3]);
2815
+ xx[i][2] = 0.5 * (xx[i][1] + xxm);
2816
+ yy[i][2] = 0.5 * (yy[i][1] + yym);
2817
+ xx[i][5] = 0.5 * (xxm + xx[i][6]);
2818
+ yy[i][5] = 0.5 * (yym + yy[i][6]);
2819
+ xx[i][3] = xx[i][4] = 0.5 * (xx[i][2] + xx[i][5]);
2820
+ yy[i][3] = yy[i][4] = 0.5 * (yy[i][2] + yy[i][5]);
2821
+ xx[i][7] = patch->x[i][3];
2822
+ yy[i][7] = patch->y[i][3];
2823
+ }
2824
+ for (i = 0; i < 4; ++i) {
2825
+ patch00.x[0][i] = xx[0][i];
2826
+ patch00.y[0][i] = yy[0][i];
2827
+ patch00.x[1][i] = 0.5 * (xx[0][i] + xx[1][i]);
2828
+ patch00.y[1][i] = 0.5 * (yy[0][i] + yy[1][i]);
2829
+ xxm = 0.5 * (xx[1][i] + xx[2][i]);
2830
+ yym = 0.5 * (yy[1][i] + yy[2][i]);
2831
+ patch10.x[2][i] = 0.5 * (xx[2][i] + xx[3][i]);
2832
+ patch10.y[2][i] = 0.5 * (yy[2][i] + yy[3][i]);
2833
+ patch00.x[2][i] = 0.5 * (patch00.x[1][i] + xxm);
2834
+ patch00.y[2][i] = 0.5 * (patch00.y[1][i] + yym);
2835
+ patch10.x[1][i] = 0.5 * (xxm + patch10.x[2][i]);
2836
+ patch10.y[1][i] = 0.5 * (yym + patch10.y[2][i]);
2837
+ patch00.x[3][i] = 0.5 * (patch00.x[2][i] + patch10.x[1][i]);
2838
+ patch00.y[3][i] = 0.5 * (patch00.y[2][i] + patch10.y[1][i]);
2839
+ patch10.x[0][i] = patch00.x[3][i];
2840
+ patch10.y[0][i] = patch00.y[3][i];
2841
+ patch10.x[3][i] = xx[3][i];
2842
+ patch10.y[3][i] = yy[3][i];
2843
+ }
2844
+ for (i = 4; i < 8; ++i) {
2845
+ patch01.x[0][i-4] = xx[0][i];
2846
+ patch01.y[0][i-4] = yy[0][i];
2847
+ patch01.x[1][i-4] = 0.5 * (xx[0][i] + xx[1][i]);
2848
+ patch01.y[1][i-4] = 0.5 * (yy[0][i] + yy[1][i]);
2849
+ xxm = 0.5 * (xx[1][i] + xx[2][i]);
2850
+ yym = 0.5 * (yy[1][i] + yy[2][i]);
2851
+ patch11.x[2][i-4] = 0.5 * (xx[2][i] + xx[3][i]);
2852
+ patch11.y[2][i-4] = 0.5 * (yy[2][i] + yy[3][i]);
2853
+ patch01.x[2][i-4] = 0.5 * (patch01.x[1][i-4] + xxm);
2854
+ patch01.y[2][i-4] = 0.5 * (patch01.y[1][i-4] + yym);
2855
+ patch11.x[1][i-4] = 0.5 * (xxm + patch11.x[2][i-4]);
2856
+ patch11.y[1][i-4] = 0.5 * (yym + patch11.y[2][i-4]);
2857
+ patch01.x[3][i-4] = 0.5 * (patch01.x[2][i-4] + patch11.x[1][i-4]);
2858
+ patch01.y[3][i-4] = 0.5 * (patch01.y[2][i-4] + patch11.y[1][i-4]);
2859
+ patch11.x[0][i-4] = patch01.x[3][i-4];
2860
+ patch11.y[0][i-4] = patch01.y[3][i-4];
2861
+ patch11.x[3][i-4] = xx[3][i];
2862
+ patch11.y[3][i-4] = yy[3][i];
2863
+ }
2864
+ //~ if the shading has a Function, this should interpolate on the
2865
+ //~ function parameter, not on the color components
2866
+ for (i = 0; i < nComps; ++i) {
2867
+ patch00.color[0][0].c[i] = patch->color[0][0].c[i];
2868
+ patch00.color[0][1].c[i] = (patch->color[0][0].c[i] +
2869
+ patch->color[0][1].c[i]) / 2;
2870
+ patch01.color[0][0].c[i] = patch00.color[0][1].c[i];
2871
+ patch01.color[0][1].c[i] = patch->color[0][1].c[i];
2872
+ patch01.color[1][1].c[i] = (patch->color[0][1].c[i] +
2873
+ patch->color[1][1].c[i]) / 2;
2874
+ patch11.color[0][1].c[i] = patch01.color[1][1].c[i];
2875
+ patch11.color[1][1].c[i] = patch->color[1][1].c[i];
2876
+ patch11.color[1][0].c[i] = (patch->color[1][1].c[i] +
2877
+ patch->color[1][0].c[i]) / 2;
2878
+ patch10.color[1][1].c[i] = patch11.color[1][0].c[i];
2879
+ patch10.color[1][0].c[i] = patch->color[1][0].c[i];
2880
+ patch10.color[0][0].c[i] = (patch->color[1][0].c[i] +
2881
+ patch->color[0][0].c[i]) / 2;
2882
+ patch00.color[1][0].c[i] = patch10.color[0][0].c[i];
2883
+ patch00.color[1][1].c[i] = (patch00.color[1][0].c[i] +
2884
+ patch01.color[1][1].c[i]) / 2;
2885
+ patch01.color[1][0].c[i] = patch00.color[1][1].c[i];
2886
+ patch11.color[0][0].c[i] = patch00.color[1][1].c[i];
2887
+ patch10.color[0][1].c[i] = patch00.color[1][1].c[i];
2888
+ }
2889
+ fillPatch(&patch00, nComps, depth + 1);
2890
+ fillPatch(&patch10, nComps, depth + 1);
2891
+ fillPatch(&patch01, nComps, depth + 1);
2892
+ fillPatch(&patch11, nComps, depth + 1);
2893
+ }
2894
+ }
2895
+
2896
+ void Gfx::doEndPath() {
2897
+ if (state->isCurPt() && clip != clipNone) {
2898
+ state->clip();
2899
+ if (clip == clipNormal) {
2900
+ out->clip(state);
2901
+ } else {
2902
+ out->eoClip(state);
2903
+ }
2904
+ }
2905
+ clip = clipNone;
2906
+ state->clearPath();
2907
+ }
2908
+
2909
+ //------------------------------------------------------------------------
2910
+ // path clipping operators
2911
+ //------------------------------------------------------------------------
2912
+
2913
+ void Gfx::opClip(Object args[], int numArgs) {
2914
+ clip = clipNormal;
2915
+ }
2916
+
2917
+ void Gfx::opEOClip(Object args[], int numArgs) {
2918
+ clip = clipEO;
2919
+ }
2920
+
2921
+ //------------------------------------------------------------------------
2922
+ // text object operators
2923
+ //------------------------------------------------------------------------
2924
+
2925
+ void Gfx::opBeginText(Object args[], int numArgs) {
2926
+ state->setTextMat(1, 0, 0, 1, 0, 0);
2927
+ state->textMoveTo(0, 0);
2928
+ out->updateTextMat(state);
2929
+ out->updateTextPos(state);
2930
+ fontChanged = gTrue;
2931
+ }
2932
+
2933
+ void Gfx::opEndText(Object args[], int numArgs) {
2934
+ out->endTextObject(state);
2935
+ }
2936
+
2937
+ //------------------------------------------------------------------------
2938
+ // text state operators
2939
+ //------------------------------------------------------------------------
2940
+
2941
+ void Gfx::opSetCharSpacing(Object args[], int numArgs) {
2942
+ state->setCharSpace(args[0].getNum());
2943
+ out->updateCharSpace(state);
2944
+ }
2945
+
2946
+ void Gfx::opSetFont(Object args[], int numArgs) {
2947
+ GfxFont *font;
2948
+
2949
+ if (!(font = res->lookupFont(args[0].getName()))) {
2950
+ return;
2951
+ }
2952
+ if (printCommands) {
2953
+ printf(" font: tag=%s name='%s' %g\n",
2954
+ font->getTag()->getCString(),
2955
+ font->getName() ? font->getName()->getCString() : "???",
2956
+ args[1].getNum());
2957
+ fflush(stdout);
2958
+ }
2959
+ state->setFont(font, args[1].getNum());
2960
+ fontChanged = gTrue;
2961
+ }
2962
+
2963
+ void Gfx::opSetTextLeading(Object args[], int numArgs) {
2964
+ state->setLeading(args[0].getNum());
2965
+ }
2966
+
2967
+ void Gfx::opSetTextRender(Object args[], int numArgs) {
2968
+ state->setRender(args[0].getInt());
2969
+ out->updateRender(state);
2970
+ }
2971
+
2972
+ void Gfx::opSetTextRise(Object args[], int numArgs) {
2973
+ state->setRise(args[0].getNum());
2974
+ out->updateRise(state);
2975
+ }
2976
+
2977
+ void Gfx::opSetWordSpacing(Object args[], int numArgs) {
2978
+ state->setWordSpace(args[0].getNum());
2979
+ out->updateWordSpace(state);
2980
+ }
2981
+
2982
+ void Gfx::opSetHorizScaling(Object args[], int numArgs) {
2983
+ state->setHorizScaling(args[0].getNum());
2984
+ out->updateHorizScaling(state);
2985
+ fontChanged = gTrue;
2986
+ }
2987
+
2988
+ //------------------------------------------------------------------------
2989
+ // text positioning operators
2990
+ //------------------------------------------------------------------------
2991
+
2992
+ void Gfx::opTextMove(Object args[], int numArgs) {
2993
+ double tx, ty;
2994
+
2995
+ tx = state->getLineX() + args[0].getNum();
2996
+ ty = state->getLineY() + args[1].getNum();
2997
+ state->textMoveTo(tx, ty);
2998
+ out->updateTextPos(state);
2999
+ }
3000
+
3001
+ void Gfx::opTextMoveSet(Object args[], int numArgs) {
3002
+ double tx, ty;
3003
+
3004
+ tx = state->getLineX() + args[0].getNum();
3005
+ ty = args[1].getNum();
3006
+ state->setLeading(-ty);
3007
+ ty += state->getLineY();
3008
+ state->textMoveTo(tx, ty);
3009
+ out->updateTextPos(state);
3010
+ }
3011
+
3012
+ void Gfx::opSetTextMatrix(Object args[], int numArgs) {
3013
+ state->setTextMat(args[0].getNum(), args[1].getNum(),
3014
+ args[2].getNum(), args[3].getNum(),
3015
+ args[4].getNum(), args[5].getNum());
3016
+ state->textMoveTo(0, 0);
3017
+ out->updateTextMat(state);
3018
+ out->updateTextPos(state);
3019
+ fontChanged = gTrue;
3020
+ }
3021
+
3022
+ void Gfx::opTextNextLine(Object args[], int numArgs) {
3023
+ double tx, ty;
3024
+
3025
+ tx = state->getLineX();
3026
+ ty = state->getLineY() - state->getLeading();
3027
+ state->textMoveTo(tx, ty);
3028
+ out->updateTextPos(state);
3029
+ }
3030
+
3031
+ //------------------------------------------------------------------------
3032
+ // text string operators
3033
+ //------------------------------------------------------------------------
3034
+
3035
+ void Gfx::opShowText(Object args[], int numArgs) {
3036
+ if (!state->getFont()) {
3037
+ error(getPos(), "No font in show");
3038
+ return;
3039
+ }
3040
+ if (fontChanged) {
3041
+ out->updateFont(state);
3042
+ fontChanged = gFalse;
3043
+ }
3044
+ out->beginStringOp(state);
3045
+ doShowText(args[0].getString());
3046
+ out->endStringOp(state);
3047
+ }
3048
+
3049
+ void Gfx::opMoveShowText(Object args[], int numArgs) {
3050
+ double tx, ty;
3051
+
3052
+ if (!state->getFont()) {
3053
+ error(getPos(), "No font in move/show");
3054
+ return;
3055
+ }
3056
+ if (fontChanged) {
3057
+ out->updateFont(state);
3058
+ fontChanged = gFalse;
3059
+ }
3060
+ tx = state->getLineX();
3061
+ ty = state->getLineY() - state->getLeading();
3062
+ state->textMoveTo(tx, ty);
3063
+ out->updateTextPos(state);
3064
+ out->beginStringOp(state);
3065
+ doShowText(args[0].getString());
3066
+ out->endStringOp(state);
3067
+ }
3068
+
3069
+ void Gfx::opMoveSetShowText(Object args[], int numArgs) {
3070
+ double tx, ty;
3071
+
3072
+ if (!state->getFont()) {
3073
+ error(getPos(), "No font in move/set/show");
3074
+ return;
3075
+ }
3076
+ if (fontChanged) {
3077
+ out->updateFont(state);
3078
+ fontChanged = gFalse;
3079
+ }
3080
+ state->setWordSpace(args[0].getNum());
3081
+ state->setCharSpace(args[1].getNum());
3082
+ tx = state->getLineX();
3083
+ ty = state->getLineY() - state->getLeading();
3084
+ state->textMoveTo(tx, ty);
3085
+ out->updateWordSpace(state);
3086
+ out->updateCharSpace(state);
3087
+ out->updateTextPos(state);
3088
+ out->beginStringOp(state);
3089
+ doShowText(args[2].getString());
3090
+ out->endStringOp(state);
3091
+ }
3092
+
3093
+ void Gfx::opShowSpaceText(Object args[], int numArgs) {
3094
+ Array *a;
3095
+ Object obj;
3096
+ int wMode;
3097
+ int i;
3098
+
3099
+ if (!state->getFont()) {
3100
+ error(getPos(), "No font in show/space");
3101
+ return;
3102
+ }
3103
+ if (fontChanged) {
3104
+ out->updateFont(state);
3105
+ fontChanged = gFalse;
3106
+ }
3107
+ out->beginStringOp(state);
3108
+ wMode = state->getFont()->getWMode();
3109
+ a = args[0].getArray();
3110
+ for (i = 0; i < a->getLength(); ++i) {
3111
+ a->get(i, &obj);
3112
+ if (obj.isNum()) {
3113
+ // this uses the absolute value of the font size to match
3114
+ // Acrobat's behavior
3115
+ if (wMode) {
3116
+ state->textShift(0, -obj.getNum() * 0.001 *
3117
+ fabs(state->getFontSize()));
3118
+ } else {
3119
+ state->textShift(-obj.getNum() * 0.001 *
3120
+ fabs(state->getFontSize()), 0);
3121
+ }
3122
+ out->updateTextShift(state, obj.getNum());
3123
+ } else if (obj.isString()) {
3124
+ doShowText(obj.getString());
3125
+ } else {
3126
+ error(getPos(), "Element of show/space array must be number or string");
3127
+ }
3128
+ obj.free();
3129
+ }
3130
+ out->endStringOp(state);
3131
+ }
3132
+
3133
+ void Gfx::doShowText(GString *s) {
3134
+ GfxFont *font;
3135
+ int wMode;
3136
+ double riseX, riseY;
3137
+ CharCode code;
3138
+ Unicode u[8];
3139
+ double x, y, dx, dy, dx2, dy2, curX, curY, tdx, tdy, lineX, lineY;
3140
+ double originX, originY, tOriginX, tOriginY;
3141
+ double oldCTM[6], newCTM[6];
3142
+ double *mat;
3143
+ Object charProc;
3144
+ Dict *resDict;
3145
+ Parser *oldParser;
3146
+ char *p;
3147
+ int len, n, uLen, nChars, nSpaces, i;
3148
+
3149
+ font = state->getFont();
3150
+ wMode = font->getWMode();
3151
+
3152
+ if (out->useDrawChar()) {
3153
+ out->beginString(state, s);
3154
+ }
3155
+
3156
+ // handle a Type 3 char
3157
+ if (font->getType() == fontType3 && out->interpretType3Chars()) {
3158
+ mat = state->getCTM();
3159
+ for (i = 0; i < 6; ++i) {
3160
+ oldCTM[i] = mat[i];
3161
+ }
3162
+ mat = state->getTextMat();
3163
+ newCTM[0] = mat[0] * oldCTM[0] + mat[1] * oldCTM[2];
3164
+ newCTM[1] = mat[0] * oldCTM[1] + mat[1] * oldCTM[3];
3165
+ newCTM[2] = mat[2] * oldCTM[0] + mat[3] * oldCTM[2];
3166
+ newCTM[3] = mat[2] * oldCTM[1] + mat[3] * oldCTM[3];
3167
+ mat = font->getFontMatrix();
3168
+ newCTM[0] = mat[0] * newCTM[0] + mat[1] * newCTM[2];
3169
+ newCTM[1] = mat[0] * newCTM[1] + mat[1] * newCTM[3];
3170
+ newCTM[2] = mat[2] * newCTM[0] + mat[3] * newCTM[2];
3171
+ newCTM[3] = mat[2] * newCTM[1] + mat[3] * newCTM[3];
3172
+ newCTM[0] *= state->getFontSize();
3173
+ newCTM[1] *= state->getFontSize();
3174
+ newCTM[2] *= state->getFontSize();
3175
+ newCTM[3] *= state->getFontSize();
3176
+ newCTM[0] *= state->getHorizScaling();
3177
+ newCTM[2] *= state->getHorizScaling();
3178
+ state->textTransformDelta(0, state->getRise(), &riseX, &riseY);
3179
+ curX = state->getCurX();
3180
+ curY = state->getCurY();
3181
+ lineX = state->getLineX();
3182
+ lineY = state->getLineY();
3183
+ oldParser = parser;
3184
+ p = s->getCString();
3185
+ len = s->getLength();
3186
+ while (len > 0) {
3187
+ n = font->getNextChar(p, len, &code,
3188
+ u, (int)(sizeof(u) / sizeof(Unicode)), &uLen,
3189
+ &dx, &dy, &originX, &originY);
3190
+ dx = dx * state->getFontSize() + state->getCharSpace();
3191
+ if (n == 1 && *p == ' ') {
3192
+ dx += state->getWordSpace();
3193
+ }
3194
+ dx *= state->getHorizScaling();
3195
+ dy *= state->getFontSize();
3196
+ state->textTransformDelta(dx, dy, &tdx, &tdy);
3197
+ state->transform(curX + riseX, curY + riseY, &x, &y);
3198
+ saveState();
3199
+ state->setCTM(newCTM[0], newCTM[1], newCTM[2], newCTM[3], x, y);
3200
+ //~ the CTM concat values here are wrong (but never used)
3201
+ out->updateCTM(state, 1, 0, 0, 1, 0, 0);
3202
+ if (!out->beginType3Char(state, curX + riseX, curY + riseY, tdx, tdy,
3203
+ code, u, uLen)) {
3204
+ ((Gfx8BitFont *)font)->getCharProc(code, &charProc);
3205
+ if ((resDict = ((Gfx8BitFont *)font)->getResources())) {
3206
+ pushResources(resDict);
3207
+ }
3208
+ if (charProc.isStream()) {
3209
+ display(&charProc, gFalse);
3210
+ } else {
3211
+ error(getPos(), "Missing or bad Type3 CharProc entry");
3212
+ }
3213
+ out->endType3Char(state);
3214
+ if (resDict) {
3215
+ popResources();
3216
+ }
3217
+ charProc.free();
3218
+ }
3219
+ restoreState();
3220
+ // GfxState::restore() does *not* restore the current position,
3221
+ // so we deal with it here using (curX, curY) and (lineX, lineY)
3222
+ curX += tdx;
3223
+ curY += tdy;
3224
+ state->moveTo(curX, curY);
3225
+ state->textSetPos(lineX, lineY);
3226
+ p += n;
3227
+ len -= n;
3228
+ }
3229
+ parser = oldParser;
3230
+
3231
+ } else if (out->useDrawChar()) {
3232
+ state->textTransformDelta(0, state->getRise(), &riseX, &riseY);
3233
+ p = s->getCString();
3234
+ len = s->getLength();
3235
+ while (len > 0) {
3236
+ n = font->getNextChar(p, len, &code,
3237
+ u, (int)(sizeof(u) / sizeof(Unicode)), &uLen,
3238
+ &dx, &dy, &originX, &originY);
3239
+ if (wMode) {
3240
+ dx *= state->getFontSize();
3241
+ dy = dy * state->getFontSize() + state->getCharSpace();
3242
+ if (n == 1 && *p == ' ') {
3243
+ dy += state->getWordSpace();
3244
+ }
3245
+ } else {
3246
+ dx = dx * state->getFontSize() + state->getCharSpace();
3247
+ if (n == 1 && *p == ' ') {
3248
+ dx += state->getWordSpace();
3249
+ }
3250
+ dx *= state->getHorizScaling();
3251
+ dy *= state->getFontSize();
3252
+ }
3253
+ state->textTransformDelta(dx, dy, &tdx, &tdy);
3254
+ originX *= state->getFontSize();
3255
+ originY *= state->getFontSize();
3256
+ state->textTransformDelta(originX, originY, &tOriginX, &tOriginY);
3257
+ out->drawChar(state, state->getCurX() + riseX, state->getCurY() + riseY,
3258
+ tdx, tdy, tOriginX, tOriginY, code, n, u, uLen);
3259
+ state->shift(tdx, tdy);
3260
+ p += n;
3261
+ len -= n;
3262
+ }
3263
+
3264
+ } else {
3265
+ dx = dy = 0;
3266
+ p = s->getCString();
3267
+ len = s->getLength();
3268
+ nChars = nSpaces = 0;
3269
+ while (len > 0) {
3270
+ n = font->getNextChar(p, len, &code,
3271
+ u, (int)(sizeof(u) / sizeof(Unicode)), &uLen,
3272
+ &dx2, &dy2, &originX, &originY);
3273
+ dx += dx2;
3274
+ dy += dy2;
3275
+ if (n == 1 && *p == ' ') {
3276
+ ++nSpaces;
3277
+ }
3278
+ ++nChars;
3279
+ p += n;
3280
+ len -= n;
3281
+ }
3282
+ if (wMode) {
3283
+ dx *= state->getFontSize();
3284
+ dy = dy * state->getFontSize()
3285
+ + nChars * state->getCharSpace()
3286
+ + nSpaces * state->getWordSpace();
3287
+ } else {
3288
+ dx = dx * state->getFontSize()
3289
+ + nChars * state->getCharSpace()
3290
+ + nSpaces * state->getWordSpace();
3291
+ dx *= state->getHorizScaling();
3292
+ dy *= state->getFontSize();
3293
+ }
3294
+ state->textTransformDelta(dx, dy, &tdx, &tdy);
3295
+ out->drawString(state, s);
3296
+ state->shift(tdx, tdy);
3297
+ }
3298
+
3299
+ if (out->useDrawChar()) {
3300
+ out->endString(state);
3301
+ }
3302
+
3303
+ updateLevel += 10 * s->getLength();
3304
+ }
3305
+
3306
+ //------------------------------------------------------------------------
3307
+ // XObject operators
3308
+ //------------------------------------------------------------------------
3309
+
3310
+ void Gfx::opXObject(Object args[], int numArgs) {
3311
+ char *name;
3312
+ Object obj1, obj2, obj3, refObj;
3313
+ #if OPI_SUPPORT
3314
+ Object opiDict;
3315
+ #endif
3316
+
3317
+ name = args[0].getName();
3318
+ if (!res->lookupXObject(name, &obj1)) {
3319
+ return;
3320
+ }
3321
+ if (!obj1.isStream()) {
3322
+ error(getPos(), "XObject '%s' is wrong type", name);
3323
+ obj1.free();
3324
+ return;
3325
+ }
3326
+ #if OPI_SUPPORT
3327
+ obj1.streamGetDict()->lookup("OPI", &opiDict);
3328
+ if (opiDict.isDict()) {
3329
+ out->opiBegin(state, opiDict.getDict());
3330
+ }
3331
+ #endif
3332
+ obj1.streamGetDict()->lookup("Subtype", &obj2);
3333
+ if (obj2.isName("Image")) {
3334
+ if (out->needNonText()) {
3335
+ res->lookupXObjectNF(name, &refObj);
3336
+ doImage(&refObj, obj1.getStream(), gFalse);
3337
+ refObj.free();
3338
+ }
3339
+ } else if (obj2.isName("Form")) {
3340
+ res->lookupXObjectNF(name, &refObj);
3341
+ if (out->useDrawForm() && refObj.isRef()) {
3342
+ out->drawForm(refObj.getRef());
3343
+ } else {
3344
+ doForm(&obj1);
3345
+ }
3346
+ refObj.free();
3347
+ } else if (obj2.isName("PS")) {
3348
+ obj1.streamGetDict()->lookup("Level1", &obj3);
3349
+ out->psXObject(obj1.getStream(),
3350
+ obj3.isStream() ? obj3.getStream() : (Stream *)NULL);
3351
+ } else if (obj2.isName()) {
3352
+ error(getPos(), "Unknown XObject subtype '%s'", obj2.getName());
3353
+ } else {
3354
+ error(getPos(), "XObject subtype is missing or wrong type");
3355
+ }
3356
+ obj2.free();
3357
+ #if OPI_SUPPORT
3358
+ if (opiDict.isDict()) {
3359
+ out->opiEnd(state, opiDict.getDict());
3360
+ }
3361
+ opiDict.free();
3362
+ #endif
3363
+ obj1.free();
3364
+ }
3365
+
3366
+ void Gfx::doImage(Object *ref, Stream *str, GBool inlineImg) {
3367
+ Dict *dict, *maskDict;
3368
+ int width, height;
3369
+ int bits, maskBits;
3370
+ StreamColorSpaceMode csMode;
3371
+ GBool mask;
3372
+ GBool invert;
3373
+ GfxColorSpace *colorSpace, *maskColorSpace;
3374
+ GfxImageColorMap *colorMap, *maskColorMap;
3375
+ Object maskObj, smaskObj;
3376
+ GBool haveColorKeyMask, haveExplicitMask, haveSoftMask;
3377
+ int maskColors[2*gfxColorMaxComps];
3378
+ int maskWidth, maskHeight;
3379
+ GBool maskInvert;
3380
+ Stream *maskStr;
3381
+ Object obj1, obj2;
3382
+ int i;
3383
+
3384
+ // get info from the stream
3385
+ bits = 0;
3386
+ csMode = streamCSNone;
3387
+ str->getImageParams(&bits, &csMode);
3388
+
3389
+ // get stream dict
3390
+ dict = str->getDict();
3391
+
3392
+ // get size
3393
+ dict->lookup("Width", &obj1);
3394
+ if (obj1.isNull()) {
3395
+ obj1.free();
3396
+ dict->lookup("W", &obj1);
3397
+ }
3398
+ if (!obj1.isInt())
3399
+ goto err2;
3400
+ width = obj1.getInt();
3401
+ obj1.free();
3402
+ dict->lookup("Height", &obj1);
3403
+ if (obj1.isNull()) {
3404
+ obj1.free();
3405
+ dict->lookup("H", &obj1);
3406
+ }
3407
+ if (!obj1.isInt())
3408
+ goto err2;
3409
+ height = obj1.getInt();
3410
+ obj1.free();
3411
+
3412
+ // image or mask?
3413
+ dict->lookup("ImageMask", &obj1);
3414
+ if (obj1.isNull()) {
3415
+ obj1.free();
3416
+ dict->lookup("IM", &obj1);
3417
+ }
3418
+ mask = gFalse;
3419
+ if (obj1.isBool())
3420
+ mask = obj1.getBool();
3421
+ else if (!obj1.isNull())
3422
+ goto err2;
3423
+ obj1.free();
3424
+
3425
+ // bit depth
3426
+ if (bits == 0) {
3427
+ dict->lookup("BitsPerComponent", &obj1);
3428
+ if (obj1.isNull()) {
3429
+ obj1.free();
3430
+ dict->lookup("BPC", &obj1);
3431
+ }
3432
+ if (obj1.isInt()) {
3433
+ bits = obj1.getInt();
3434
+ } else if (mask) {
3435
+ bits = 1;
3436
+ } else {
3437
+ goto err2;
3438
+ }
3439
+ obj1.free();
3440
+ }
3441
+
3442
+ // display a mask
3443
+ if (mask) {
3444
+
3445
+ // check for inverted mask
3446
+ if (bits != 1)
3447
+ goto err1;
3448
+ invert = gFalse;
3449
+ dict->lookup("Decode", &obj1);
3450
+ if (obj1.isNull()) {
3451
+ obj1.free();
3452
+ dict->lookup("D", &obj1);
3453
+ }
3454
+ if (obj1.isArray()) {
3455
+ obj1.arrayGet(0, &obj2);
3456
+ if (obj2.isInt() && obj2.getInt() == 1)
3457
+ invert = gTrue;
3458
+ obj2.free();
3459
+ } else if (!obj1.isNull()) {
3460
+ goto err2;
3461
+ }
3462
+ obj1.free();
3463
+
3464
+ // draw it
3465
+ out->drawImageMask(state, ref, str, width, height, invert, inlineImg);
3466
+
3467
+ } else {
3468
+
3469
+ // get color space and color map
3470
+ dict->lookup("ColorSpace", &obj1);
3471
+ if (obj1.isNull()) {
3472
+ obj1.free();
3473
+ dict->lookup("CS", &obj1);
3474
+ }
3475
+ if (obj1.isName()) {
3476
+ res->lookupColorSpace(obj1.getName(), &obj2);
3477
+ if (!obj2.isNull()) {
3478
+ obj1.free();
3479
+ obj1 = obj2;
3480
+ } else {
3481
+ obj2.free();
3482
+ }
3483
+ }
3484
+ if (!obj1.isNull()) {
3485
+ colorSpace = GfxColorSpace::parse(&obj1);
3486
+ } else if (csMode == streamCSDeviceGray) {
3487
+ colorSpace = new GfxDeviceGrayColorSpace();
3488
+ } else if (csMode == streamCSDeviceRGB) {
3489
+ colorSpace = new GfxDeviceRGBColorSpace();
3490
+ } else if (csMode == streamCSDeviceCMYK) {
3491
+ colorSpace = new GfxDeviceCMYKColorSpace();
3492
+ } else {
3493
+ colorSpace = NULL;
3494
+ }
3495
+ obj1.free();
3496
+ if (!colorSpace) {
3497
+ goto err1;
3498
+ }
3499
+ dict->lookup("Decode", &obj1);
3500
+ if (obj1.isNull()) {
3501
+ obj1.free();
3502
+ dict->lookup("D", &obj1);
3503
+ }
3504
+ colorMap = new GfxImageColorMap(bits, &obj1, colorSpace);
3505
+ obj1.free();
3506
+ if (!colorMap->isOk()) {
3507
+ delete colorMap;
3508
+ goto err1;
3509
+ }
3510
+
3511
+ // get the mask
3512
+ haveColorKeyMask = haveExplicitMask = haveSoftMask = gFalse;
3513
+ maskStr = NULL; // make gcc happy
3514
+ maskWidth = maskHeight = 0; // make gcc happy
3515
+ maskInvert = gFalse; // make gcc happy
3516
+ maskColorMap = NULL; // make gcc happy
3517
+ dict->lookup("Mask", &maskObj);
3518
+ dict->lookup("SMask", &smaskObj);
3519
+ if (smaskObj.isStream()) {
3520
+ // soft mask
3521
+ if (inlineImg) {
3522
+ goto err1;
3523
+ }
3524
+ maskStr = smaskObj.getStream();
3525
+ maskDict = smaskObj.streamGetDict();
3526
+ maskDict->lookup("Width", &obj1);
3527
+ if (obj1.isNull()) {
3528
+ obj1.free();
3529
+ maskDict->lookup("W", &obj1);
3530
+ }
3531
+ if (!obj1.isInt()) {
3532
+ goto err2;
3533
+ }
3534
+ maskWidth = obj1.getInt();
3535
+ obj1.free();
3536
+ maskDict->lookup("Height", &obj1);
3537
+ if (obj1.isNull()) {
3538
+ obj1.free();
3539
+ maskDict->lookup("H", &obj1);
3540
+ }
3541
+ if (!obj1.isInt()) {
3542
+ goto err2;
3543
+ }
3544
+ maskHeight = obj1.getInt();
3545
+ obj1.free();
3546
+ maskDict->lookup("BitsPerComponent", &obj1);
3547
+ if (obj1.isNull()) {
3548
+ obj1.free();
3549
+ maskDict->lookup("BPC", &obj1);
3550
+ }
3551
+ if (!obj1.isInt()) {
3552
+ goto err2;
3553
+ }
3554
+ maskBits = obj1.getInt();
3555
+ obj1.free();
3556
+ maskDict->lookup("ColorSpace", &obj1);
3557
+ if (obj1.isNull()) {
3558
+ obj1.free();
3559
+ maskDict->lookup("CS", &obj1);
3560
+ }
3561
+ if (obj1.isName()) {
3562
+ res->lookupColorSpace(obj1.getName(), &obj2);
3563
+ if (!obj2.isNull()) {
3564
+ obj1.free();
3565
+ obj1 = obj2;
3566
+ } else {
3567
+ obj2.free();
3568
+ }
3569
+ }
3570
+ maskColorSpace = GfxColorSpace::parse(&obj1);
3571
+ obj1.free();
3572
+ if (!maskColorSpace || maskColorSpace->getMode() != csDeviceGray) {
3573
+ goto err1;
3574
+ }
3575
+ maskDict->lookup("Decode", &obj1);
3576
+ if (obj1.isNull()) {
3577
+ obj1.free();
3578
+ maskDict->lookup("D", &obj1);
3579
+ }
3580
+ maskColorMap = new GfxImageColorMap(maskBits, &obj1, maskColorSpace);
3581
+ obj1.free();
3582
+ if (!maskColorMap->isOk()) {
3583
+ delete maskColorMap;
3584
+ goto err1;
3585
+ }
3586
+ //~ handle the Matte entry
3587
+ haveSoftMask = gTrue;
3588
+ } else if (maskObj.isArray()) {
3589
+ // color key mask
3590
+ for (i = 0;
3591
+ i < maskObj.arrayGetLength() && i < 2*gfxColorMaxComps;
3592
+ ++i) {
3593
+ maskObj.arrayGet(i, &obj1);
3594
+ maskColors[i] = obj1.getInt();
3595
+ obj1.free();
3596
+ }
3597
+ haveColorKeyMask = gTrue;
3598
+ } else if (maskObj.isStream()) {
3599
+ // explicit mask
3600
+ if (inlineImg) {
3601
+ goto err1;
3602
+ }
3603
+ maskStr = maskObj.getStream();
3604
+ maskDict = maskObj.streamGetDict();
3605
+ maskDict->lookup("Width", &obj1);
3606
+ if (obj1.isNull()) {
3607
+ obj1.free();
3608
+ maskDict->lookup("W", &obj1);
3609
+ }
3610
+ if (!obj1.isInt()) {
3611
+ goto err2;
3612
+ }
3613
+ maskWidth = obj1.getInt();
3614
+ obj1.free();
3615
+ maskDict->lookup("Height", &obj1);
3616
+ if (obj1.isNull()) {
3617
+ obj1.free();
3618
+ maskDict->lookup("H", &obj1);
3619
+ }
3620
+ if (!obj1.isInt()) {
3621
+ goto err2;
3622
+ }
3623
+ maskHeight = obj1.getInt();
3624
+ obj1.free();
3625
+ maskDict->lookup("ImageMask", &obj1);
3626
+ if (obj1.isNull()) {
3627
+ obj1.free();
3628
+ maskDict->lookup("IM", &obj1);
3629
+ }
3630
+ if (!obj1.isBool() || !obj1.getBool()) {
3631
+ goto err2;
3632
+ }
3633
+ obj1.free();
3634
+ maskInvert = gFalse;
3635
+ maskDict->lookup("Decode", &obj1);
3636
+ if (obj1.isNull()) {
3637
+ obj1.free();
3638
+ maskDict->lookup("D", &obj1);
3639
+ }
3640
+ if (obj1.isArray()) {
3641
+ obj1.arrayGet(0, &obj2);
3642
+ if (obj2.isInt() && obj2.getInt() == 1) {
3643
+ maskInvert = gTrue;
3644
+ }
3645
+ obj2.free();
3646
+ } else if (!obj1.isNull()) {
3647
+ goto err2;
3648
+ }
3649
+ obj1.free();
3650
+ haveExplicitMask = gTrue;
3651
+ }
3652
+
3653
+ // draw it
3654
+ if (haveSoftMask) {
3655
+ out->drawSoftMaskedImage(state, ref, str, width, height, colorMap,
3656
+ maskStr, maskWidth, maskHeight, maskColorMap);
3657
+ delete maskColorMap;
3658
+ } else if (haveExplicitMask) {
3659
+ out->drawMaskedImage(state, ref, str, width, height, colorMap,
3660
+ maskStr, maskWidth, maskHeight, maskInvert);
3661
+ } else {
3662
+ out->drawImage(state, ref, str, width, height, colorMap,
3663
+ haveColorKeyMask ? maskColors : (int *)NULL, inlineImg);
3664
+ }
3665
+ delete colorMap;
3666
+
3667
+ maskObj.free();
3668
+ smaskObj.free();
3669
+ }
3670
+
3671
+ if ((i = width * height) > 1000) {
3672
+ i = 1000;
3673
+ }
3674
+ updateLevel += i;
3675
+
3676
+ return;
3677
+
3678
+ err2:
3679
+ obj1.free();
3680
+ err1:
3681
+ error(getPos(), "Bad image parameters");
3682
+ }
3683
+
3684
+ void Gfx::doForm(Object *str) {
3685
+ Dict *dict;
3686
+ GBool transpGroup, isolated, knockout;
3687
+ GfxColorSpace *blendingColorSpace;
3688
+ Object matrixObj, bboxObj;
3689
+ double m[6], bbox[4];
3690
+ Object resObj;
3691
+ Dict *resDict;
3692
+ Object obj1, obj2, obj3;
3693
+ int i;
3694
+
3695
+ // check for excessive recursion
3696
+ if (formDepth > 20) {
3697
+ return;
3698
+ }
3699
+
3700
+ // get stream dict
3701
+ dict = str->streamGetDict();
3702
+
3703
+ // check form type
3704
+ dict->lookup("FormType", &obj1);
3705
+ if (!(obj1.isNull() || (obj1.isInt() && obj1.getInt() == 1))) {
3706
+ error(getPos(), "Unknown form type");
3707
+ }
3708
+ obj1.free();
3709
+
3710
+ // get bounding box
3711
+ dict->lookup("BBox", &bboxObj);
3712
+ if (!bboxObj.isArray()) {
3713
+ bboxObj.free();
3714
+ error(getPos(), "Bad form bounding box");
3715
+ return;
3716
+ }
3717
+ for (i = 0; i < 4; ++i) {
3718
+ bboxObj.arrayGet(i, &obj1);
3719
+ bbox[i] = obj1.getNum();
3720
+ obj1.free();
3721
+ }
3722
+ bboxObj.free();
3723
+
3724
+ // get matrix
3725
+ dict->lookup("Matrix", &matrixObj);
3726
+ if (matrixObj.isArray()) {
3727
+ for (i = 0; i < 6; ++i) {
3728
+ matrixObj.arrayGet(i, &obj1);
3729
+ m[i] = obj1.getNum();
3730
+ obj1.free();
3731
+ }
3732
+ } else {
3733
+ m[0] = 1; m[1] = 0;
3734
+ m[2] = 0; m[3] = 1;
3735
+ m[4] = 0; m[5] = 0;
3736
+ }
3737
+ matrixObj.free();
3738
+
3739
+ // get resources
3740
+ dict->lookup("Resources", &resObj);
3741
+ resDict = resObj.isDict() ? resObj.getDict() : (Dict *)NULL;
3742
+
3743
+ // check for a transparency group
3744
+ transpGroup = isolated = knockout = gFalse;
3745
+ blendingColorSpace = NULL;
3746
+ if (dict->lookup("Group", &obj1)->isDict()) {
3747
+ if (obj1.dictLookup("S", &obj2)->isName("Transparency")) {
3748
+ transpGroup = gTrue;
3749
+ if (!obj1.dictLookup("CS", &obj3)->isNull()) {
3750
+ blendingColorSpace = GfxColorSpace::parse(&obj3);
3751
+ }
3752
+ obj3.free();
3753
+ if (obj1.dictLookup("I", &obj3)->isBool()) {
3754
+ isolated = obj3.getBool();
3755
+ }
3756
+ obj3.free();
3757
+ if (obj1.dictLookup("K", &obj3)->isBool()) {
3758
+ knockout = obj3.getBool();
3759
+ }
3760
+ obj3.free();
3761
+ }
3762
+ obj2.free();
3763
+ }
3764
+ obj1.free();
3765
+
3766
+ // draw it
3767
+ ++formDepth;
3768
+ doForm1(str, resDict, m, bbox,
3769
+ transpGroup, gFalse, blendingColorSpace, isolated, knockout);
3770
+ --formDepth;
3771
+
3772
+ if (blendingColorSpace) {
3773
+ delete blendingColorSpace;
3774
+ }
3775
+ resObj.free();
3776
+ }
3777
+
3778
+ void Gfx::doForm1(Object *str, Dict *resDict, double *matrix, double *bbox,
3779
+ GBool transpGroup, GBool softMask,
3780
+ GfxColorSpace *blendingColorSpace,
3781
+ GBool isolated, GBool knockout,
3782
+ GBool alpha, Function *transferFunc,
3783
+ GfxColor *backdropColor) {
3784
+ Parser *oldParser;
3785
+ double oldBaseMatrix[6];
3786
+ int i;
3787
+
3788
+ // push new resources on stack
3789
+ pushResources(resDict);
3790
+
3791
+ // save current graphics state
3792
+ saveState();
3793
+
3794
+ // kill any pre-existing path
3795
+ state->clearPath();
3796
+
3797
+ // save current parser
3798
+ oldParser = parser;
3799
+
3800
+ // set form transformation matrix
3801
+ state->concatCTM(matrix[0], matrix[1], matrix[2],
3802
+ matrix[3], matrix[4], matrix[5]);
3803
+ out->updateCTM(state, matrix[0], matrix[1], matrix[2],
3804
+ matrix[3], matrix[4], matrix[5]);
3805
+
3806
+ // set form bounding box
3807
+ state->moveTo(bbox[0], bbox[1]);
3808
+ state->lineTo(bbox[2], bbox[1]);
3809
+ state->lineTo(bbox[2], bbox[3]);
3810
+ state->lineTo(bbox[0], bbox[3]);
3811
+ state->closePath();
3812
+ state->clip();
3813
+ out->clip(state);
3814
+ state->clearPath();
3815
+
3816
+ if (softMask || transpGroup) {
3817
+ if (state->getBlendMode() != gfxBlendNormal) {
3818
+ state->setBlendMode(gfxBlendNormal);
3819
+ out->updateBlendMode(state);
3820
+ }
3821
+ if (state->getFillOpacity() != 1) {
3822
+ state->setFillOpacity(1);
3823
+ out->updateFillOpacity(state);
3824
+ }
3825
+ if (state->getStrokeOpacity() != 1) {
3826
+ state->setStrokeOpacity(1);
3827
+ out->updateStrokeOpacity(state);
3828
+ }
3829
+ out->clearSoftMask(state);
3830
+ out->beginTransparencyGroup(state, bbox, blendingColorSpace,
3831
+ isolated, knockout, softMask);
3832
+ }
3833
+
3834
+ // set new base matrix
3835
+ for (i = 0; i < 6; ++i) {
3836
+ oldBaseMatrix[i] = baseMatrix[i];
3837
+ baseMatrix[i] = state->getCTM()[i];
3838
+ }
3839
+
3840
+ // draw the form
3841
+ display(str, gFalse);
3842
+
3843
+ if (softMask || transpGroup) {
3844
+ out->endTransparencyGroup(state);
3845
+ }
3846
+
3847
+ // restore base matrix
3848
+ for (i = 0; i < 6; ++i) {
3849
+ baseMatrix[i] = oldBaseMatrix[i];
3850
+ }
3851
+
3852
+ // restore parser
3853
+ parser = oldParser;
3854
+
3855
+ // restore graphics state
3856
+ restoreState();
3857
+
3858
+ // pop resource stack
3859
+ popResources();
3860
+
3861
+ if (softMask) {
3862
+ out->setSoftMask(state, bbox, alpha, transferFunc, backdropColor);
3863
+ } else if (transpGroup) {
3864
+ out->paintTransparencyGroup(state, bbox);
3865
+ }
3866
+
3867
+ return;
3868
+ }
3869
+
3870
+ //------------------------------------------------------------------------
3871
+ // in-line image operators
3872
+ //------------------------------------------------------------------------
3873
+
3874
+ void Gfx::opBeginImage(Object args[], int numArgs) {
3875
+ Stream *str;
3876
+ int c1, c2;
3877
+
3878
+ // build dict/stream
3879
+ str = buildImageStream();
3880
+
3881
+ // display the image
3882
+ if (str) {
3883
+ doImage(NULL, str, gTrue);
3884
+
3885
+ // skip 'EI' tag
3886
+ c1 = str->getUndecodedStream()->getChar();
3887
+ c2 = str->getUndecodedStream()->getChar();
3888
+ while (!(c1 == 'E' && c2 == 'I') && c2 != EOF) {
3889
+ c1 = c2;
3890
+ c2 = str->getUndecodedStream()->getChar();
3891
+ }
3892
+ delete str;
3893
+ }
3894
+ }
3895
+
3896
+ Stream *Gfx::buildImageStream() {
3897
+ Object dict;
3898
+ Object obj;
3899
+ char *key;
3900
+ Stream *str;
3901
+
3902
+ // build dictionary
3903
+ dict.initDict(xref);
3904
+ parser->getObj(&obj);
3905
+ while (!obj.isCmd("ID") && !obj.isEOF()) {
3906
+ if (!obj.isName()) {
3907
+ error(getPos(), "Inline image dictionary key must be a name object");
3908
+ obj.free();
3909
+ } else {
3910
+ key = copyString(obj.getName());
3911
+ obj.free();
3912
+ parser->getObj(&obj);
3913
+ if (obj.isEOF() || obj.isError()) {
3914
+ gfree(key);
3915
+ break;
3916
+ }
3917
+ dict.dictAdd(key, &obj);
3918
+ }
3919
+ parser->getObj(&obj);
3920
+ }
3921
+ if (obj.isEOF()) {
3922
+ error(getPos(), "End of file in inline image");
3923
+ obj.free();
3924
+ dict.free();
3925
+ return NULL;
3926
+ }
3927
+ obj.free();
3928
+
3929
+ // make stream
3930
+ str = new EmbedStream(parser->getStream(), &dict, gFalse, 0);
3931
+ str = str->addFilters(&dict);
3932
+
3933
+ return str;
3934
+ }
3935
+
3936
+ void Gfx::opImageData(Object args[], int numArgs) {
3937
+ error(getPos(), "Internal: got 'ID' operator");
3938
+ }
3939
+
3940
+ void Gfx::opEndImage(Object args[], int numArgs) {
3941
+ error(getPos(), "Internal: got 'EI' operator");
3942
+ }
3943
+
3944
+ //------------------------------------------------------------------------
3945
+ // type 3 font operators
3946
+ //------------------------------------------------------------------------
3947
+
3948
+ void Gfx::opSetCharWidth(Object args[], int numArgs) {
3949
+ out->type3D0(state, args[0].getNum(), args[1].getNum());
3950
+ }
3951
+
3952
+ void Gfx::opSetCacheDevice(Object args[], int numArgs) {
3953
+ out->type3D1(state, args[0].getNum(), args[1].getNum(),
3954
+ args[2].getNum(), args[3].getNum(),
3955
+ args[4].getNum(), args[5].getNum());
3956
+ }
3957
+
3958
+ //------------------------------------------------------------------------
3959
+ // compatibility operators
3960
+ //------------------------------------------------------------------------
3961
+
3962
+ void Gfx::opBeginIgnoreUndef(Object args[], int numArgs) {
3963
+ ++ignoreUndef;
3964
+ }
3965
+
3966
+ void Gfx::opEndIgnoreUndef(Object args[], int numArgs) {
3967
+ if (ignoreUndef > 0)
3968
+ --ignoreUndef;
3969
+ }
3970
+
3971
+ //------------------------------------------------------------------------
3972
+ // marked content operators
3973
+ //------------------------------------------------------------------------
3974
+
3975
+ void Gfx::opBeginMarkedContent(Object args[], int numArgs) {
3976
+ if (printCommands) {
3977
+ printf(" marked content: %s ", args[0].getName());
3978
+ if (numArgs == 2)
3979
+ args[2].print(stdout);
3980
+ printf("\n");
3981
+ fflush(stdout);
3982
+ }
3983
+ }
3984
+
3985
+ void Gfx::opEndMarkedContent(Object args[], int numArgs) {
3986
+ }
3987
+
3988
+ void Gfx::opMarkPoint(Object args[], int numArgs) {
3989
+ if (printCommands) {
3990
+ printf(" mark point: %s ", args[0].getName());
3991
+ if (numArgs == 2)
3992
+ args[2].print(stdout);
3993
+ printf("\n");
3994
+ fflush(stdout);
3995
+ }
3996
+ }
3997
+
3998
+ //------------------------------------------------------------------------
3999
+ // misc
4000
+ //------------------------------------------------------------------------
4001
+
4002
+ void Gfx::drawAnnot(Object *str, AnnotBorderStyle *borderStyle,
4003
+ double xMin, double yMin, double xMax, double yMax) {
4004
+ Dict *dict, *resDict;
4005
+ Object matrixObj, bboxObj, resObj;
4006
+ Object obj1;
4007
+ double m[6], bbox[4], ictm[6];
4008
+ double *ctm;
4009
+ double formX0, formY0, formX1, formY1;
4010
+ double annotX0, annotY0, annotX1, annotY1;
4011
+ double det, x, y, sx, sy;
4012
+ double r, g, b;
4013
+ GfxColor color;
4014
+ double *dash, *dash2;
4015
+ int dashLength;
4016
+ int i;
4017
+
4018
+ //~ can we assume that we're in default user space?
4019
+ //~ (i.e., baseMatrix = ctm)
4020
+
4021
+ // transform the annotation bbox from default user space to user
4022
+ // space: (bbox * baseMatrix) * iCTM
4023
+ ctm = state->getCTM();
4024
+ det = 1 / (ctm[0] * ctm[3] - ctm[1] * ctm[2]);
4025
+ ictm[0] = ctm[3] * det;
4026
+ ictm[1] = -ctm[1] * det;
4027
+ ictm[2] = -ctm[2] * det;
4028
+ ictm[3] = ctm[0] * det;
4029
+ ictm[4] = (ctm[2] * ctm[5] - ctm[3] * ctm[4]) * det;
4030
+ ictm[5] = (ctm[1] * ctm[4] - ctm[0] * ctm[5]) * det;
4031
+ x = baseMatrix[0] * xMin + baseMatrix[2] * yMin + baseMatrix[4];
4032
+ y = baseMatrix[1] * xMin + baseMatrix[3] * yMin + baseMatrix[5];
4033
+ annotX0 = ictm[0] * x + ictm[2] * y + ictm[4];
4034
+ annotY0 = ictm[1] * x + ictm[3] * y + ictm[5];
4035
+ x = baseMatrix[0] * xMax + baseMatrix[2] * yMax + baseMatrix[4];
4036
+ y = baseMatrix[1] * xMax + baseMatrix[3] * yMax + baseMatrix[5];
4037
+ annotX1 = ictm[0] * x + ictm[2] * y + ictm[4];
4038
+ annotY1 = ictm[1] * x + ictm[3] * y + ictm[5];
4039
+ if (annotX0 > annotX1) {
4040
+ x = annotX0; annotX0 = annotX1; annotX1 = x;
4041
+ }
4042
+ if (annotY0 > annotY1) {
4043
+ y = annotY0; annotY0 = annotY1; annotY1 = y;
4044
+ }
4045
+
4046
+ // draw the appearance stream (if there is one)
4047
+ if (str->isStream()) {
4048
+
4049
+ // get stream dict
4050
+ dict = str->streamGetDict();
4051
+
4052
+ // get the form bounding box
4053
+ dict->lookup("BBox", &bboxObj);
4054
+ if (!bboxObj.isArray()) {
4055
+ bboxObj.free();
4056
+ error(getPos(), "Bad form bounding box");
4057
+ return;
4058
+ }
4059
+ for (i = 0; i < 4; ++i) {
4060
+ bboxObj.arrayGet(i, &obj1);
4061
+ bbox[i] = obj1.getNum();
4062
+ obj1.free();
4063
+ }
4064
+ bboxObj.free();
4065
+
4066
+ // get the form matrix
4067
+ dict->lookup("Matrix", &matrixObj);
4068
+ if (matrixObj.isArray()) {
4069
+ for (i = 0; i < 6; ++i) {
4070
+ matrixObj.arrayGet(i, &obj1);
4071
+ m[i] = obj1.getNum();
4072
+ obj1.free();
4073
+ }
4074
+ } else {
4075
+ m[0] = 1; m[1] = 0;
4076
+ m[2] = 0; m[3] = 1;
4077
+ m[4] = 0; m[5] = 0;
4078
+ }
4079
+ matrixObj.free();
4080
+
4081
+ // transform the form bbox from form space to user space
4082
+ formX0 = bbox[0] * m[0] + bbox[1] * m[2] + m[4];
4083
+ formY0 = bbox[0] * m[1] + bbox[1] * m[3] + m[5];
4084
+ formX1 = bbox[2] * m[0] + bbox[3] * m[2] + m[4];
4085
+ formY1 = bbox[2] * m[1] + bbox[3] * m[3] + m[5];
4086
+ if (formX0 > formX1) {
4087
+ x = formX0; formX0 = formX1; formX1 = x;
4088
+ }
4089
+ if (formY0 > formY1) {
4090
+ y = formY0; formY0 = formY1; formY1 = y;
4091
+ }
4092
+
4093
+ // scale the form to fit the annotation bbox
4094
+ if (formX1 == formX0) {
4095
+ // this shouldn't happen
4096
+ sx = 1;
4097
+ } else {
4098
+ sx = (annotX1 - annotX0) / (formX1 - formX0);
4099
+ }
4100
+ if (formY1 == formY0) {
4101
+ // this shouldn't happen
4102
+ sy = 1;
4103
+ } else {
4104
+ sy = (annotY1 - annotY0) / (formY1 - formY0);
4105
+ }
4106
+ m[0] *= sx;
4107
+ m[2] *= sx;
4108
+ m[4] = (m[4] - formX0) * sx + annotX0;
4109
+ m[1] *= sy;
4110
+ m[3] *= sy;
4111
+ m[5] = (m[5] - formY0) * sy + annotY0;
4112
+
4113
+ // get resources
4114
+ dict->lookup("Resources", &resObj);
4115
+ resDict = resObj.isDict() ? resObj.getDict() : (Dict *)NULL;
4116
+
4117
+ // draw it
4118
+ doForm1(str, resDict, m, bbox);
4119
+
4120
+ resObj.free();
4121
+ }
4122
+
4123
+ // draw the border
4124
+ if (borderStyle && borderStyle->getWidth() > 0) {
4125
+ if (state->getStrokeColorSpace()->getMode() != csDeviceRGB) {
4126
+ state->setStrokePattern(NULL);
4127
+ state->setStrokeColorSpace(new GfxDeviceRGBColorSpace());
4128
+ out->updateStrokeColorSpace(state);
4129
+ }
4130
+ borderStyle->getColor(&r, &g, &b);
4131
+ color.c[0] = dblToCol(r);
4132
+ color.c[1] = dblToCol(g);
4133
+ color.c[2] = dblToCol(b);
4134
+ state->setStrokeColor(&color);
4135
+ out->updateStrokeColor(state);
4136
+ // compute the width scale factor when going from default user
4137
+ // space to user space
4138
+ x = (baseMatrix[0] + baseMatrix[2]) * ictm[0] +
4139
+ (baseMatrix[1] + baseMatrix[3]) * ictm[2];
4140
+ y = (baseMatrix[0] + baseMatrix[2]) * ictm[1] +
4141
+ (baseMatrix[1] + baseMatrix[3]) * ictm[3];
4142
+ x = sqrt(0.5 * (x * x + y * y));
4143
+ state->setLineWidth(x * borderStyle->getWidth());
4144
+ out->updateLineWidth(state);
4145
+ borderStyle->getDash(&dash, &dashLength);
4146
+ if (borderStyle->getType() == annotBorderDashed && dashLength > 0) {
4147
+ dash2 = (double *)gmallocn(dashLength, sizeof(double));
4148
+ for (i = 0; i < dashLength; ++i) {
4149
+ dash2[i] = x * dash[i];
4150
+ }
4151
+ state->setLineDash(dash2, dashLength, 0);
4152
+ out->updateLineDash(state);
4153
+ }
4154
+ //~ this doesn't currently handle the beveled and engraved styles
4155
+ state->clearPath();
4156
+ state->moveTo(annotX0, out->upsideDown() ? annotY1 : annotY0);
4157
+ state->lineTo(annotX1, out->upsideDown() ? annotY1 : annotY0);
4158
+ if (borderStyle->getType() != annotBorderUnderlined) {
4159
+ state->lineTo(annotX1, out->upsideDown() ? annotY0 : annotY1);
4160
+ state->lineTo(annotX0, out->upsideDown() ? annotY0 : annotY1);
4161
+ state->closePath();
4162
+ }
4163
+ out->stroke(state);
4164
+ }
4165
+ }
4166
+
4167
+ void Gfx::saveState() {
4168
+ out->saveState(state);
4169
+ state = state->save();
4170
+ }
4171
+
4172
+ void Gfx::restoreState() {
4173
+ state = state->restore();
4174
+ out->restoreState(state);
4175
+ }
4176
+
4177
+ void Gfx::pushResources(Dict *resDict) {
4178
+ res = new GfxResources(xref, resDict, res);
4179
+ }
4180
+
4181
+ void Gfx::popResources() {
4182
+ GfxResources *resPtr;
4183
+
4184
+ resPtr = res->getNext();
4185
+ delete res;
4186
+ res = resPtr;
4187
+ }