pdf2json 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
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
+ }