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

PDFFactory.java 50KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282
  1. /*
  2. * Copyright 1999-2004 The Apache Software Foundation.
  3. *
  4. * Licensed under the Apache License, Version 2.0 (the "License");
  5. * you may not use this file except in compliance with the License.
  6. * You may obtain a copy of the License at
  7. *
  8. * http://www.apache.org/licenses/LICENSE-2.0
  9. *
  10. * Unless required by applicable law or agreed to in writing, software
  11. * distributed under the License is distributed on an "AS IS" BASIS,
  12. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13. * See the License for the specific language governing permissions and
  14. * limitations under the License.
  15. */
  16. /* $Id$ */
  17. package org.apache.fop.pdf;
  18. // Java
  19. import java.awt.geom.Rectangle2D;
  20. import java.io.IOException;
  21. import java.io.InputStream;
  22. import java.util.List;
  23. import java.util.Map;
  24. // Apache libs
  25. import org.apache.avalon.framework.container.ContainerUtil;
  26. import org.apache.commons.io.IOUtils;
  27. // FOP
  28. import org.apache.fop.fonts.CIDFont;
  29. import org.apache.fop.fonts.CustomFont;
  30. import org.apache.fop.fonts.Typeface;
  31. import org.apache.fop.fonts.FontDescriptor;
  32. import org.apache.fop.fonts.FontMetrics;
  33. import org.apache.fop.fonts.FontType;
  34. import org.apache.fop.fonts.LazyFont;
  35. import org.apache.fop.fonts.MultiByteFont;
  36. import org.apache.fop.fonts.truetype.FontFileReader;
  37. import org.apache.fop.fonts.truetype.TTFSubSetFile;
  38. import org.apache.fop.fonts.type1.PFBData;
  39. import org.apache.fop.fonts.type1.PFBParser;
  40. /**
  41. * This class provides method to create and register PDF objects.
  42. */
  43. public class PDFFactory {
  44. private PDFDocument document;
  45. /**
  46. * Creates a new PDFFactory.
  47. * @param document the parent PDFDocument needed to register the generated
  48. * objects
  49. */
  50. public PDFFactory(PDFDocument document) {
  51. this.document = document;
  52. }
  53. /**
  54. * Returns the parent PDFDocument associated with this factory.
  55. * @return PDFDocument the parent PDFDocument
  56. */
  57. public final PDFDocument getDocument() {
  58. return this.document;
  59. }
  60. /* ========================= structure objects ========================= */
  61. /**
  62. * Make a /Catalog (Root) object. This object is written in
  63. * the trailer.
  64. *
  65. * @param pages the pages pdf object that the root points to
  66. * @return the new pdf root object for this document
  67. */
  68. public PDFRoot makeRoot(PDFPages pages) {
  69. //Make a /Pages object. This object is written in the trailer.
  70. PDFRoot pdfRoot = new PDFRoot(++this.document.objectcount, pages);
  71. getDocument().addTrailerObject(pdfRoot);
  72. return pdfRoot;
  73. }
  74. /**
  75. * Make a /Pages object. This object is written in the trailer.
  76. *
  77. * @return a new PDF Pages object for adding pages to
  78. */
  79. public PDFPages makePages() {
  80. PDFPages pdfPages = new PDFPages(++this.document.objectcount);
  81. getDocument().addTrailerObject(pdfPages);
  82. return pdfPages;
  83. }
  84. /**
  85. * Make a /Resources object. This object is written in the trailer.
  86. *
  87. * @return a new PDF resources object
  88. */
  89. public PDFResources makeResources() {
  90. PDFResources pdfResources = new PDFResources(++this.document.objectcount);
  91. getDocument().addTrailerObject(pdfResources);
  92. return pdfResources;
  93. }
  94. /**
  95. * make an /Info object
  96. *
  97. * @param prod string indicating application producing the PDF
  98. * @return the created /Info object
  99. */
  100. protected PDFInfo makeInfo(String prod) {
  101. /*
  102. * create a PDFInfo with the next object number and add to
  103. * list of objects
  104. */
  105. PDFInfo pdfInfo = new PDFInfo();
  106. // set the default producer
  107. pdfInfo.setProducer(prod);
  108. getDocument().registerObject(pdfInfo);
  109. return pdfInfo;
  110. }
  111. /**
  112. * Make a /Page object. The page is assigned an object number immediately
  113. * so references can already be made. The page must be added to the
  114. * PDFDocument later using addObject().
  115. *
  116. * @param resources resources object to use
  117. * @param pagewidth width of the page in points
  118. * @param pageheight height of the page in points
  119. *
  120. * @return the created /Page object
  121. */
  122. public PDFPage makePage(PDFResources resources,
  123. int pagewidth, int pageheight) {
  124. /*
  125. * create a PDFPage with the next object number, the given
  126. * resources, contents and dimensions
  127. */
  128. PDFPage page = new PDFPage(resources,
  129. pagewidth, pageheight);
  130. getDocument().assignObjectNumber(page);
  131. getDocument().getPages().addPage(page);
  132. return page;
  133. }
  134. /* ========================= functions ================================= */
  135. /**
  136. * Make a Type 0 sampled function
  137. *
  138. * @param theDomain List objects of Double objects.
  139. * This is the domain of the function.
  140. * See page 264 of the PDF 1.3 Spec.
  141. * @param theRange List objects of Double objects.
  142. * This is the Range of the function.
  143. * See page 264 of the PDF 1.3 Spec.
  144. * @param theSize A List object of Integer objects.
  145. * This is the number of samples in each input dimension.
  146. * I can't imagine there being more or less than two input dimensions,
  147. * so maybe this should be an array of length 2.
  148. *
  149. * See page 265 of the PDF 1.3 Spec.
  150. * @param theBitsPerSample An int specifying the number of bits user
  151. * to represent each sample value.
  152. * Limited to 1,2,4,8,12,16,24 or 32.
  153. * See page 265 of the 1.3 PDF Spec.
  154. * @param theOrder The order of interpolation between samples.
  155. * Default is 1 (one). Limited
  156. * to 1 (one) or 3, which means linear or cubic-spline interpolation.
  157. *
  158. * This attribute is optional.
  159. *
  160. * See page 265 in the PDF 1.3 spec.
  161. * @param theEncode List objects of Double objects.
  162. * This is the linear mapping of input values intop the domain
  163. * of the function's sample table. Default is hard to represent in
  164. * ascii, but basically [0 (Size0 1) 0 (Size1 1)...].
  165. * This attribute is optional.
  166. *
  167. * See page 265 in the PDF 1.3 spec.
  168. * @param theDecode List objects of Double objects.
  169. * This is a linear mapping of sample values into the range.
  170. * The default is just the range.
  171. *
  172. * This attribute is optional.
  173. * Read about it on page 265 of the PDF 1.3 spec.
  174. * @param theFunctionDataStream The sample values that specify
  175. * the function are provided in a stream.
  176. *
  177. * This is optional, but is almost always used.
  178. *
  179. * Page 265 of the PDF 1.3 spec has more.
  180. * @param theFilter This is a vector of String objects which
  181. * are the various filters that have are to be
  182. * applied to the stream to make sense of it.
  183. * Order matters, so watch out.
  184. *
  185. * This is not documented in the Function section of the PDF 1.3 spec,
  186. * it was deduced from samples that this is sometimes used, even if we may never
  187. * use it in FOP. It is added for completeness sake.
  188. * @param theFunctionType This is the type of function (0,2,3, or 4).
  189. * It should be 0 as this is the constructor for sampled functions.
  190. * @return the PDF function that was created
  191. */
  192. public PDFFunction makeFunction(int theFunctionType, List theDomain,
  193. List theRange, List theSize,
  194. int theBitsPerSample, int theOrder,
  195. List theEncode, List theDecode,
  196. StringBuffer theFunctionDataStream,
  197. List theFilter) {
  198. // Type 0 function
  199. PDFFunction function = new PDFFunction(theFunctionType, theDomain,
  200. theRange, theSize,
  201. theBitsPerSample, theOrder,
  202. theEncode, theDecode,
  203. theFunctionDataStream,
  204. theFilter);
  205. PDFFunction oldfunc = getDocument().findFunction(function);
  206. if (oldfunc == null) {
  207. getDocument().registerObject(function);
  208. } else {
  209. function = oldfunc;
  210. }
  211. return (function);
  212. }
  213. /**
  214. * make a type Exponential interpolation function
  215. * (for shading usually)
  216. *
  217. * @param theDomain List objects of Double objects.
  218. * This is the domain of the function.
  219. * See page 264 of the PDF 1.3 Spec.
  220. * @param theRange List of Doubles that is the Range of the function.
  221. * See page 264 of the PDF 1.3 Spec.
  222. * @param theCZero This is a vector of Double objects which defines the function result
  223. * when x=0.
  224. *
  225. * This attribute is optional.
  226. * It's described on page 268 of the PDF 1.3 spec.
  227. * @param theCOne This is a vector of Double objects which defines the function result
  228. * when x=1.
  229. *
  230. * This attribute is optional.
  231. * It's described on page 268 of the PDF 1.3 spec.
  232. * @param theInterpolationExponentN This is the inerpolation exponent.
  233. *
  234. * This attribute is required.
  235. * PDF Spec page 268
  236. * @param theFunctionType The type of the function, which should be 2.
  237. * @return the PDF function that was created
  238. */
  239. public PDFFunction makeFunction(int theFunctionType, List theDomain,
  240. List theRange, List theCZero,
  241. List theCOne,
  242. double theInterpolationExponentN) { // type 2
  243. PDFFunction function = new PDFFunction(theFunctionType, theDomain,
  244. theRange, theCZero, theCOne,
  245. theInterpolationExponentN);
  246. PDFFunction oldfunc = getDocument().findFunction(function);
  247. if (oldfunc == null) {
  248. getDocument().registerObject(function);
  249. } else {
  250. function = oldfunc;
  251. }
  252. return (function);
  253. }
  254. /**
  255. * Make a Type 3 Stitching function
  256. *
  257. * @param theDomain List objects of Double objects.
  258. * This is the domain of the function.
  259. * See page 264 of the PDF 1.3 Spec.
  260. * @param theRange List objects of Double objects.
  261. * This is the Range of the function.
  262. * See page 264 of the PDF 1.3 Spec.
  263. * @param theFunctions An List of the PDFFunction objects
  264. * that the stitching function stitches.
  265. *
  266. * This attributed is required.
  267. * It is described on page 269 of the PDF spec.
  268. * @param theBounds This is a vector of Doubles representing
  269. * the numbers that, in conjunction with Domain
  270. * define the intervals to which each function from
  271. * the 'functions' object applies. It must be in
  272. * order of increasing magnitude, and each must be
  273. * within Domain.
  274. *
  275. * It basically sets how much of the gradient each function handles.
  276. *
  277. * This attributed is required.
  278. * It's described on page 269 of the PDF 1.3 spec.
  279. * @param theEncode List objects of Double objects.
  280. * This is the linear mapping of input values intop the domain
  281. * of the function's sample table. Default is hard to represent in
  282. * ascii, but basically [0 (Size0 1) 0 (Size1 1)...].
  283. * This attribute is required.
  284. *
  285. * See page 270 in the PDF 1.3 spec.
  286. * @param theFunctionType This is the function type. It should be 3,
  287. * for a stitching function.
  288. * @return the PDF function that was created
  289. */
  290. public PDFFunction makeFunction(int theFunctionType, List theDomain,
  291. List theRange, List theFunctions,
  292. List theBounds,
  293. List theEncode) {
  294. // Type 3
  295. PDFFunction function = new PDFFunction(theFunctionType, theDomain,
  296. theRange, theFunctions,
  297. theBounds, theEncode);
  298. PDFFunction oldfunc = getDocument().findFunction(function);
  299. if (oldfunc == null) {
  300. getDocument().registerObject(function);
  301. } else {
  302. function = oldfunc;
  303. }
  304. return (function);
  305. }
  306. /**
  307. * make a postscript calculator function
  308. *
  309. * @param theNumber the PDF object number
  310. * @param theFunctionType the type of function to make
  311. * @param theDomain the domain values
  312. * @param theRange the range values of the function
  313. * @param theFunctionDataStream a string containing the pdf drawing
  314. * @return the PDF function that was created
  315. */
  316. public PDFFunction makeFunction(int theNumber, int theFunctionType,
  317. List theDomain, List theRange,
  318. StringBuffer theFunctionDataStream) {
  319. // Type 4
  320. PDFFunction function = new PDFFunction(theFunctionType, theDomain,
  321. theRange,
  322. theFunctionDataStream);
  323. PDFFunction oldfunc = getDocument().findFunction(function);
  324. if (oldfunc == null) {
  325. getDocument().registerObject(function);
  326. } else {
  327. function = oldfunc;
  328. }
  329. return (function);
  330. }
  331. /* ========================= shadings ================================== */
  332. /**
  333. * make a function based shading object
  334. *
  335. * @param res the PDF resource context to add the shading, may be null
  336. * @param theShadingType The type of shading object, which should be 1 for function
  337. * based shading.
  338. * @param theColorSpace The colorspace is 'DeviceRGB' or something similar.
  339. * @param theBackground An array of color components appropriate to the
  340. * colorspace key specifying a single color value.
  341. * This key is used by the f operator buy ignored by the sh operator.
  342. * @param theBBox List of double's representing a rectangle
  343. * in the coordinate space that is current at the
  344. * time of shading is imaged. Temporary clipping
  345. * boundary.
  346. * @param theAntiAlias Whether or not to anti-alias.
  347. * @param theDomain Optional vector of Doubles specifying the domain.
  348. * @param theMatrix List of Doubles specifying the matrix.
  349. * If it's a pattern, then the matrix maps it to pattern space.
  350. * If it's a shading, then it maps it to current user space.
  351. * It's optional, the default is the identity matrix
  352. * @param theFunction The PDF Function that maps an (x,y) location to a color
  353. * @return the PDF shading that was created
  354. */
  355. public PDFShading makeShading(PDFResourceContext res, int theShadingType,
  356. PDFColorSpace theColorSpace,
  357. List theBackground, List theBBox,
  358. boolean theAntiAlias, List theDomain,
  359. List theMatrix,
  360. PDFFunction theFunction) {
  361. // make Shading of Type 1
  362. PDFShading shading = new PDFShading(theShadingType,
  363. theColorSpace, theBackground,
  364. theBBox, theAntiAlias, theDomain,
  365. theMatrix, theFunction);
  366. PDFShading oldshad = getDocument().findShading(shading);
  367. if (oldshad == null) {
  368. getDocument().registerObject(shading);
  369. } else {
  370. shading = oldshad;
  371. }
  372. // add this shading to resources
  373. if (res != null) {
  374. res.getPDFResources().addShading(shading);
  375. } else {
  376. getDocument().getResources().addShading(shading);
  377. }
  378. return (shading);
  379. }
  380. /**
  381. * Make an axial or radial shading object.
  382. *
  383. * @param res the PDF resource context to add the shading, may be null
  384. * @param theShadingType 2 or 3 for axial or radial shading
  385. * @param theColorSpace "DeviceRGB" or similar.
  386. * @param theBackground theBackground An array of color components appropriate to the
  387. * colorspace key specifying a single color value.
  388. * This key is used by the f operator buy ignored by the sh operator.
  389. * @param theBBox List of double's representing a rectangle
  390. * in the coordinate space that is current at the
  391. * time of shading is imaged. Temporary clipping
  392. * boundary.
  393. * @param theAntiAlias Default is false
  394. * @param theCoords List of four (type 2) or 6 (type 3) Double
  395. * @param theDomain List of Doubles specifying the domain
  396. * @param theFunction the Stitching (PDFfunction type 3) function,
  397. * even if it's stitching a single function
  398. * @param theExtend List of Booleans of whether to extend the
  399. * start and end colors past the start and end points
  400. * The default is [false, false]
  401. * @return the PDF shading that was created
  402. */
  403. public PDFShading makeShading(PDFResourceContext res, int theShadingType,
  404. PDFColorSpace theColorSpace,
  405. List theBackground, List theBBox,
  406. boolean theAntiAlias, List theCoords,
  407. List theDomain, PDFFunction theFunction,
  408. List theExtend) {
  409. // make Shading of Type 2 or 3
  410. PDFShading shading = new PDFShading(theShadingType,
  411. theColorSpace, theBackground,
  412. theBBox, theAntiAlias, theCoords,
  413. theDomain, theFunction,
  414. theExtend);
  415. PDFShading oldshad = getDocument().findShading(shading);
  416. if (oldshad == null) {
  417. getDocument().registerObject(shading);
  418. } else {
  419. shading = oldshad;
  420. }
  421. if (res != null) {
  422. res.getPDFResources().addShading(shading);
  423. } else {
  424. getDocument().getResources().addShading(shading);
  425. }
  426. return (shading);
  427. }
  428. /**
  429. * Make a free-form gouraud shaded triangle mesh, coons patch mesh, or tensor patch mesh
  430. * shading object
  431. *
  432. * @param res the PDF resource context to add the shading, may be null
  433. * @param theShadingType 4, 6, or 7 depending on whether it's
  434. * Free-form gouraud-shaded triangle meshes, coons patch meshes,
  435. * or tensor product patch meshes, respectively.
  436. * @param theColorSpace "DeviceRGB" or similar.
  437. * @param theBackground theBackground An array of color components appropriate to the
  438. * colorspace key specifying a single color value.
  439. * This key is used by the f operator buy ignored by the sh operator.
  440. * @param theBBox List of double's representing a rectangle
  441. * in the coordinate space that is current at the
  442. * time of shading is imaged. Temporary clipping
  443. * boundary.
  444. * @param theAntiAlias Default is false
  445. * @param theBitsPerCoordinate 1,2,4,8,12,16,24 or 32.
  446. * @param theBitsPerComponent 1,2,4,8,12, and 16
  447. * @param theBitsPerFlag 2,4,8.
  448. * @param theDecode List of Doubles see PDF 1.3 spec pages 303 to 312.
  449. * @param theFunction the PDFFunction
  450. * @return the PDF shading that was created
  451. */
  452. public PDFShading makeShading(PDFResourceContext res, int theShadingType,
  453. PDFColorSpace theColorSpace,
  454. List theBackground, List theBBox,
  455. boolean theAntiAlias,
  456. int theBitsPerCoordinate,
  457. int theBitsPerComponent,
  458. int theBitsPerFlag, List theDecode,
  459. PDFFunction theFunction) {
  460. // make Shading of type 4,6 or 7
  461. PDFShading shading = new PDFShading(theShadingType,
  462. theColorSpace, theBackground,
  463. theBBox, theAntiAlias,
  464. theBitsPerCoordinate,
  465. theBitsPerComponent,
  466. theBitsPerFlag, theDecode,
  467. theFunction);
  468. PDFShading oldshad = getDocument().findShading(shading);
  469. if (oldshad == null) {
  470. getDocument().registerObject(shading);
  471. } else {
  472. shading = oldshad;
  473. }
  474. if (res != null) {
  475. res.getPDFResources().addShading(shading);
  476. } else {
  477. getDocument().getResources().addShading(shading);
  478. }
  479. return (shading);
  480. }
  481. /**
  482. * make a Lattice-Form Gouraud mesh shading object
  483. *
  484. * @param res the PDF resource context to add the shading, may be null
  485. * @param theShadingType 5 for lattice-Form Gouraud shaded-triangle mesh
  486. * without spaces. "Shading1" or "Sh1" are good examples.
  487. * @param theColorSpace "DeviceRGB" or similar.
  488. * @param theBackground theBackground An array of color components appropriate to the
  489. * colorspace key specifying a single color value.
  490. * This key is used by the f operator buy ignored by the sh operator.
  491. * @param theBBox List of double's representing a rectangle
  492. * in the coordinate space that is current at the
  493. * time of shading is imaged. Temporary clipping
  494. * boundary.
  495. * @param theAntiAlias Default is false
  496. * @param theBitsPerCoordinate 1,2,4,8,12,16, 24, or 32
  497. * @param theBitsPerComponent 1,2,4,8,12,24,32
  498. * @param theDecode List of Doubles. See page 305 in PDF 1.3 spec.
  499. * @param theVerticesPerRow number of vertices in each "row" of the lattice.
  500. * @param theFunction The PDFFunction that's mapped on to this shape
  501. * @return the PDF shading that was created
  502. */
  503. public PDFShading makeShading(PDFResourceContext res, int theShadingType,
  504. PDFColorSpace theColorSpace,
  505. List theBackground, List theBBox,
  506. boolean theAntiAlias,
  507. int theBitsPerCoordinate,
  508. int theBitsPerComponent, List theDecode,
  509. int theVerticesPerRow,
  510. PDFFunction theFunction) {
  511. // make shading of Type 5
  512. PDFShading shading = new PDFShading(theShadingType,
  513. theColorSpace, theBackground,
  514. theBBox, theAntiAlias,
  515. theBitsPerCoordinate,
  516. theBitsPerComponent, theDecode,
  517. theVerticesPerRow, theFunction);
  518. PDFShading oldshad = getDocument().findShading(shading);
  519. if (oldshad == null) {
  520. getDocument().registerObject(shading);
  521. } else {
  522. shading = oldshad;
  523. }
  524. if (res != null) {
  525. res.getPDFResources().addShading(shading);
  526. } else {
  527. getDocument().getResources().addShading(shading);
  528. }
  529. return (shading);
  530. }
  531. /* ========================= patterns ================================== */
  532. /**
  533. * Make a tiling pattern
  534. *
  535. * @param res the PDF resource context to add the shading, may be null
  536. * @param thePatternType the type of pattern, which is 1 for tiling.
  537. * @param theResources the resources associated with this pattern
  538. * @param thePaintType 1 or 2, colored or uncolored.
  539. * @param theTilingType 1, 2, or 3, constant spacing, no distortion, or faster tiling
  540. * @param theBBox List of Doubles: The pattern cell bounding box
  541. * @param theXStep horizontal spacing
  542. * @param theYStep vertical spacing
  543. * @param theMatrix Optional List of Doubles transformation matrix
  544. * @param theXUID Optional vector of Integers that uniquely identify the pattern
  545. * @param thePatternDataStream The stream of pattern data to be tiled.
  546. * @return the PDF pattern that was created
  547. */
  548. public PDFPattern makePattern(PDFResourceContext res, int thePatternType, // 1
  549. PDFResources theResources, int thePaintType, int theTilingType,
  550. List theBBox, double theXStep,
  551. double theYStep, List theMatrix,
  552. List theXUID, StringBuffer thePatternDataStream) {
  553. // PDFResources theResources
  554. PDFPattern pattern = new PDFPattern(theResources, 1,
  555. thePaintType, theTilingType,
  556. theBBox, theXStep, theYStep,
  557. theMatrix, theXUID,
  558. thePatternDataStream);
  559. PDFPattern oldpatt = getDocument().findPattern(pattern);
  560. if (oldpatt == null) {
  561. getDocument().registerObject(pattern);
  562. } else {
  563. pattern = oldpatt;
  564. }
  565. if (res != null) {
  566. res.getPDFResources().addPattern(pattern);
  567. } else {
  568. getDocument().getResources().addPattern(pattern);
  569. }
  570. return (pattern);
  571. }
  572. /**
  573. * Make a smooth shading pattern
  574. *
  575. * @param res the PDF resource context to add the shading, may be null
  576. * @param thePatternType the type of the pattern, which is 2, smooth shading
  577. * @param theShading the PDF Shading object that comprises this pattern
  578. * @param theXUID optional:the extended unique Identifier if used.
  579. * @param theExtGState optional: the extended graphics state, if used.
  580. * @param theMatrix Optional:List of Doubles that specify the matrix.
  581. * @return the PDF pattern that was created
  582. */
  583. public PDFPattern makePattern(PDFResourceContext res,
  584. int thePatternType, PDFShading theShading,
  585. List theXUID, StringBuffer theExtGState,
  586. List theMatrix) {
  587. PDFPattern pattern = new PDFPattern(2, theShading,
  588. theXUID, theExtGState, theMatrix);
  589. PDFPattern oldpatt = getDocument().findPattern(pattern);
  590. if (oldpatt == null) {
  591. getDocument().registerObject(pattern);
  592. } else {
  593. pattern = oldpatt;
  594. }
  595. if (res != null) {
  596. res.getPDFResources().addPattern(pattern);
  597. } else {
  598. getDocument().getResources().addPattern(pattern);
  599. }
  600. return (pattern);
  601. }
  602. /**
  603. * Make a gradient
  604. *
  605. * @param res the PDF resource context to add the shading, may be null
  606. * @param radial if true a radial gradient will be created
  607. * @param theColorspace the colorspace of the gradient
  608. * @param theColors the list of colors for the gradient
  609. * @param theBounds the list of bounds associated with the colors
  610. * @param theCoords the coordinates for the gradient
  611. * @return the PDF pattern that was created
  612. */
  613. public PDFPattern makeGradient(PDFResourceContext res, boolean radial,
  614. PDFColorSpace theColorspace,
  615. List theColors, List theBounds,
  616. List theCoords) {
  617. PDFShading myShad;
  618. PDFFunction myfunky;
  619. PDFFunction myfunc;
  620. List theCzero;
  621. List theCone;
  622. PDFPattern myPattern;
  623. //PDFColorSpace theColorSpace;
  624. double interpolation = (double)1.000;
  625. List theFunctions = new java.util.ArrayList();
  626. int currentPosition;
  627. int lastPosition = theColors.size() - 1;
  628. // if 5 elements, the penultimate element is 3.
  629. // do not go beyond that, because you always need
  630. // to have a next color when creating the function.
  631. for (currentPosition = 0; currentPosition < lastPosition;
  632. currentPosition++) { // for every consecutive color pair
  633. PDFColor currentColor =
  634. (PDFColor)theColors.get(currentPosition);
  635. PDFColor nextColor = (PDFColor)theColors.get(currentPosition
  636. + 1);
  637. // colorspace must be consistant
  638. if (getDocument().getColorSpace()
  639. != currentColor.getColorSpace()) {
  640. currentColor.setColorSpace(
  641. getDocument().getColorSpace());
  642. }
  643. if (getDocument().getColorSpace()
  644. != nextColor.getColorSpace()) {
  645. nextColor.setColorSpace(
  646. getDocument().getColorSpace());
  647. }
  648. theCzero = currentColor.getVector();
  649. theCone = nextColor.getVector();
  650. myfunc = makeFunction(2, null, null, theCzero, theCone,
  651. interpolation);
  652. theFunctions.add(myfunc);
  653. } // end of for every consecutive color pair
  654. myfunky = makeFunction(3, null, null, theFunctions, theBounds,
  655. null);
  656. if (radial) {
  657. if (theCoords.size() == 6) {
  658. myShad = makeShading(res, 3, getDocument().getPDFColorSpace(),
  659. null, null,
  660. false, theCoords, null, myfunky,
  661. null);
  662. } else { // if the center x, center y, and radius specifiy
  663. // the gradient, then assume the same center x, center y,
  664. // and radius of zero for the other necessary component
  665. List newCoords = new java.util.ArrayList();
  666. newCoords.add(theCoords.get(0));
  667. newCoords.add(theCoords.get(1));
  668. newCoords.add(theCoords.get(2));
  669. newCoords.add(theCoords.get(0));
  670. newCoords.add(theCoords.get(1));
  671. newCoords.add(new Double(0.0));
  672. myShad = makeShading(res, 3, getDocument().getPDFColorSpace(),
  673. null, null,
  674. false, newCoords, null, myfunky,
  675. null);
  676. }
  677. } else {
  678. myShad = makeShading(res, 2, getDocument().getPDFColorSpace(),
  679. null, null,
  680. false, theCoords, null, myfunky,
  681. null);
  682. }
  683. myPattern = makePattern(res, 2, myShad, null, null, null);
  684. return (myPattern);
  685. }
  686. /* ========================= links ===================================== */
  687. /**
  688. * Make an internal link.
  689. *
  690. * @param rect the hotspot position in absolute coordinates
  691. * @param page the target page reference value
  692. * @param dest the position destination
  693. * @return the new PDF link object
  694. */
  695. public PDFLink makeLink(Rectangle2D rect, String page, String dest) {
  696. PDFLink link = new PDFLink(rect);
  697. getDocument().registerObject(link);
  698. PDFGoTo gt = new PDFGoTo(page);
  699. gt.setDestination(dest);
  700. getDocument().addTrailerObject(gt);
  701. PDFInternalLink internalLink = new PDFInternalLink(gt.referencePDF());
  702. link.setAction(internalLink);
  703. return link;
  704. }
  705. /**
  706. * make a link object
  707. *
  708. * @param rect the clickable rectangle
  709. * @param destination the destination file
  710. * @param linkType the link type
  711. * @param yoffset the yoffset on the page for an internal link
  712. * @return the PDFLink object created
  713. */
  714. public PDFLink makeLink(Rectangle2D rect, String destination,
  715. int linkType, float yoffset) {
  716. //PDFLink linkObject;
  717. int index;
  718. PDFLink link = new PDFLink(rect);
  719. if (linkType == PDFLink.EXTERNAL) {
  720. // check destination
  721. if (destination.startsWith("http://")) {
  722. PDFUri uri = new PDFUri(destination);
  723. link.setAction(uri);
  724. } else if (destination.endsWith(".pdf")) { // FileSpec
  725. PDFGoToRemote remote = getGoToPDFAction(destination, null, -1);
  726. link.setAction(remote);
  727. } else if ((index = destination.indexOf(".pdf#page=")) > 0) {
  728. //String file = destination.substring(0, index + 4);
  729. int page = Integer.parseInt(destination.substring(index + 10));
  730. PDFGoToRemote remote = getGoToPDFAction(destination, null, page);
  731. link.setAction(remote);
  732. } else if ((index = destination.indexOf(".pdf#dest=")) > 0) {
  733. //String file = destination.substring(0, index + 4);
  734. String dest = destination.substring(index + 10);
  735. PDFGoToRemote remote = getGoToPDFAction(destination, dest, -1);
  736. link.setAction(remote);
  737. } else { // URI
  738. PDFUri uri = new PDFUri(destination);
  739. link.setAction(uri);
  740. }
  741. } else {
  742. // linkType is internal
  743. String goToReference = getGoToReference(destination, yoffset);
  744. PDFInternalLink internalLink = new PDFInternalLink(goToReference);
  745. link.setAction(internalLink);
  746. }
  747. PDFLink oldlink = getDocument().findLink(link);
  748. if (oldlink == null) {
  749. getDocument().registerObject(link);
  750. } else {
  751. link = oldlink;
  752. }
  753. return link;
  754. }
  755. private String getGoToReference(String destination, float yoffset) {
  756. String goToReference = null;
  757. PDFGoTo gt = new PDFGoTo(destination);
  758. gt.setYPosition(yoffset);
  759. PDFGoTo oldgt = getDocument().findGoTo(gt);
  760. if (oldgt == null) {
  761. getDocument().assignObjectNumber(gt);
  762. getDocument().addTrailerObject(gt);
  763. } else {
  764. gt = oldgt;
  765. }
  766. goToReference = gt.referencePDF();
  767. return goToReference;
  768. }
  769. /**
  770. * Create and return a goto pdf document action.
  771. * This creates a pdf files spec and pdf goto remote action.
  772. * It also checks available pdf objects so it will not create an
  773. * object if it already exists.
  774. *
  775. * @param file the pdf file name
  776. * @param dest the remote name destination, may be null
  777. * @param page the remote page number, -1 means not specified
  778. * @return the pdf goto remote object
  779. */
  780. private PDFGoToRemote getGoToPDFAction(String file, String dest, int page) {
  781. PDFFileSpec fileSpec = new PDFFileSpec(file);
  782. PDFFileSpec oldspec = getDocument().findFileSpec(fileSpec);
  783. if (oldspec == null) {
  784. getDocument().registerObject(fileSpec);
  785. } else {
  786. fileSpec = oldspec;
  787. }
  788. PDFGoToRemote remote;
  789. if (dest == null && page == -1) {
  790. remote = new PDFGoToRemote(fileSpec);
  791. } else if (dest != null) {
  792. remote = new PDFGoToRemote(fileSpec, dest);
  793. } else {
  794. remote = new PDFGoToRemote(fileSpec, page);
  795. }
  796. PDFGoToRemote oldremote = getDocument().findGoToRemote(remote);
  797. if (oldremote == null) {
  798. getDocument().registerObject(remote);
  799. } else {
  800. remote = oldremote;
  801. }
  802. return remote;
  803. }
  804. /**
  805. * Make an outline object and add it to the given outline
  806. *
  807. * @param parent parent PDFOutline object which may be null
  808. * @param label the title for the new outline object
  809. * @param destination the reference string for the action to go to
  810. * @param yoffset the yoffset on the destination page
  811. * @return the new PDF outline object
  812. */
  813. public PDFOutline makeOutline(PDFOutline parent, String label,
  814. String destination, float yoffset) {
  815. String goToRef = getGoToReference(destination, yoffset);
  816. PDFOutline obj = new PDFOutline(label, goToRef);
  817. if (parent != null) {
  818. parent.addOutline(obj);
  819. }
  820. getDocument().registerObject(obj);
  821. return obj;
  822. }
  823. /* ========================= fonts ===================================== */
  824. /**
  825. * make a /Encoding object
  826. *
  827. * @param encodingName character encoding scheme name
  828. * @return the created /Encoding object
  829. */
  830. public PDFEncoding makeEncoding(String encodingName) {
  831. PDFEncoding encoding = new PDFEncoding(encodingName);
  832. getDocument().registerObject(encoding);
  833. return encoding;
  834. }
  835. /**
  836. * make a Type1 /Font object
  837. *
  838. * @param fontname internal name to use for this font (eg "F1")
  839. * @param basefont name of the base font (eg "Helvetica")
  840. * @param encoding character encoding scheme used by the font
  841. * @param metrics additional information about the font
  842. * @param descriptor additional information about the font
  843. * @return the created /Font object
  844. */
  845. public PDFFont makeFont(String fontname, String basefont,
  846. String encoding, FontMetrics metrics,
  847. FontDescriptor descriptor) {
  848. PDFFont preRegisteredfont = getDocument().findFont(fontname);
  849. if (preRegisteredfont != null) {
  850. return preRegisteredfont;
  851. }
  852. if (descriptor == null) {
  853. PDFFont font = new PDFFont(fontname, FontType.TYPE1, basefont, encoding);
  854. getDocument().registerObject(font);
  855. return font;
  856. } else {
  857. FontType fonttype = metrics.getFontType();
  858. PDFFontDescriptor pdfdesc = makeFontDescriptor(descriptor);
  859. PDFFontNonBase14 font = null;
  860. if (fonttype == FontType.TYPE0) {
  861. /*
  862. * Temporary commented out - customized CMaps
  863. * isn't needed until /ToUnicode support is added
  864. * PDFCMap cmap = new PDFCMap(++this.objectcount,
  865. * "fop-ucs-H",
  866. * new PDFCIDSystemInfo("Adobe",
  867. * "Identity",
  868. * 0));
  869. * cmap.addContents();
  870. * this.objects.add(cmap);
  871. */
  872. font =
  873. (PDFFontNonBase14)PDFFont.createFont(fontname, fonttype,
  874. basefont,
  875. "Identity-H");
  876. } else {
  877. font =
  878. (PDFFontNonBase14)PDFFont.createFont(fontname, fonttype,
  879. basefont, encoding);
  880. }
  881. getDocument().registerObject(font);
  882. font.setDescriptor(pdfdesc);
  883. if (fonttype == FontType.TYPE0) {
  884. CIDFont cidMetrics;
  885. if (metrics instanceof LazyFont) {
  886. cidMetrics = (CIDFont)((LazyFont) metrics).getRealFont();
  887. } else {
  888. cidMetrics = (CIDFont)metrics;
  889. }
  890. PDFCIDSystemInfo sysInfo =
  891. new PDFCIDSystemInfo(cidMetrics.getRegistry(),
  892. cidMetrics.getOrdering(),
  893. cidMetrics.getSupplement());
  894. PDFCIDFont cidFont =
  895. new PDFCIDFont(basefont,
  896. cidMetrics.getCIDType(),
  897. cidMetrics.getDefaultWidth(),
  898. getSubsetWidths(cidMetrics), sysInfo,
  899. (PDFCIDFontDescriptor)pdfdesc);
  900. getDocument().registerObject(cidFont);
  901. ((PDFFontType0)font).setDescendantFonts(cidFont);
  902. } else {
  903. int firstChar = 0;
  904. int lastChar = 255;
  905. if (metrics instanceof CustomFont) {
  906. CustomFont cf = (CustomFont)metrics;
  907. firstChar = cf.getFirstChar();
  908. lastChar = cf.getLastChar();
  909. }
  910. font.setWidthMetrics(firstChar,
  911. lastChar,
  912. makeArray(metrics.getWidths()));
  913. }
  914. return font;
  915. }
  916. }
  917. public PDFWArray getSubsetWidths(CIDFont cidFont) {
  918. // Create widths for reencoded chars
  919. PDFWArray warray = new PDFWArray();
  920. int[] tmpWidth = new int[cidFont.usedGlyphsCount];
  921. for (int i = 0; i < cidFont.usedGlyphsCount; i++) {
  922. Integer nw = (Integer)cidFont.usedGlyphsIndex.get(new Integer(i));
  923. int nwx = (nw == null) ? 0 : nw.intValue();
  924. tmpWidth[i] = cidFont.width[nwx];
  925. }
  926. warray.addEntry(0, tmpWidth);
  927. return warray;
  928. }
  929. /**
  930. * make a /FontDescriptor object
  931. *
  932. * @param desc the font descriptor
  933. * @return the new PDF font descriptor
  934. */
  935. public PDFFontDescriptor makeFontDescriptor(FontDescriptor desc) {
  936. PDFFontDescriptor descriptor = null;
  937. if (desc.getFontType() == FontType.TYPE0) {
  938. // CID Font
  939. descriptor = new PDFCIDFontDescriptor(desc.getFontName(),
  940. desc.getFontBBox(),
  941. desc.getCapHeight(),
  942. desc.getFlags(),
  943. desc.getItalicAngle(),
  944. desc.getStemV(), null);
  945. } else {
  946. // Create normal FontDescriptor
  947. descriptor = new PDFFontDescriptor(desc.getFontName(),
  948. desc.getAscender(),
  949. desc.getDescender(),
  950. desc.getCapHeight(),
  951. desc.getFlags(),
  952. new PDFRectangle(desc.getFontBBox()),
  953. desc.getStemV(),
  954. desc.getItalicAngle());
  955. }
  956. getDocument().registerObject(descriptor);
  957. // Check if the font is embeddable
  958. if (desc.isEmbeddable()) {
  959. AbstractPDFStream stream = makeFontFile(desc);
  960. if (stream != null) {
  961. descriptor.setFontFile(desc.getFontType(), stream);
  962. getDocument().registerObject(stream);
  963. }
  964. }
  965. return descriptor;
  966. }
  967. /**
  968. * Embeds a font.
  969. * @param desc FontDescriptor of the font.
  970. * @return PDFStream The embedded font file
  971. */
  972. public AbstractPDFStream makeFontFile(FontDescriptor desc) {
  973. if (desc.getFontType() == FontType.OTHER) {
  974. throw new IllegalArgumentException("Trying to embed unsupported font type: "
  975. + desc.getFontType());
  976. }
  977. Typeface tempFont;
  978. if (desc instanceof LazyFont) {
  979. tempFont = ((LazyFont)desc).getRealFont();
  980. } else {
  981. tempFont = (Typeface)desc;
  982. }
  983. if (!(tempFont instanceof CustomFont)) {
  984. throw new IllegalArgumentException(
  985. "FontDescriptor must be instance of CustomFont, but is a "
  986. + desc.getClass().getName());
  987. }
  988. CustomFont font = (CustomFont)tempFont;
  989. InputStream in = null;
  990. try {
  991. // Get file first
  992. if (font.getEmbedFileName() != null) {
  993. try {
  994. in = getDocument().resolveURI(font.getEmbedFileName());
  995. } catch (Exception e) {
  996. getDocument().getLogger().error("Failed to embed fontfile: "
  997. + font.getEmbedFileName()
  998. + "(" + e.getMessage() + ")");
  999. }
  1000. }
  1001. // Get resource
  1002. if (in == null && font.getEmbedResourceName() != null) {
  1003. try {
  1004. in = new java.io.BufferedInputStream(
  1005. this.getClass().getResourceAsStream(
  1006. font.getEmbedResourceName()));
  1007. } catch (Exception e) {
  1008. getDocument().getLogger().error(
  1009. "Failed to embed fontresource: "
  1010. + font.getEmbedResourceName()
  1011. + "(" + e.getMessage() + ")");
  1012. }
  1013. }
  1014. if (in == null) {
  1015. return null;
  1016. } else {
  1017. try {
  1018. AbstractPDFStream embeddedFont;
  1019. if (desc.getFontType() == FontType.TYPE0) {
  1020. MultiByteFont mbfont = (MultiByteFont)font;
  1021. FontFileReader reader = new FontFileReader(in);
  1022. TTFSubSetFile subset = new TTFSubSetFile();
  1023. ContainerUtil.enableLogging(subset,
  1024. getDocument().getLogger().getChildLogger("fonts"));
  1025. byte[] subsetFont = subset.readFont(reader,
  1026. mbfont.getTTCName(), mbfont.getUsedGlyphs());
  1027. // Only TrueType CID fonts are supported now
  1028. embeddedFont = new PDFTTFStream(subsetFont.length);
  1029. ((PDFTTFStream)embeddedFont).setData(subsetFont, subsetFont.length);
  1030. } else if (desc.getFontType() == FontType.TYPE1) {
  1031. PFBParser parser = new PFBParser();
  1032. PFBData pfb = parser.parsePFB(in);
  1033. embeddedFont = new PDFT1Stream();
  1034. ((PDFT1Stream)embeddedFont).setData(pfb);
  1035. } else {
  1036. byte[] file = IOUtils.toByteArray(in);
  1037. embeddedFont = new PDFTTFStream(file.length);
  1038. ((PDFTTFStream)embeddedFont).setData(file, file.length);
  1039. }
  1040. /*
  1041. embeddedFont.getFilterList().addFilter("flate");
  1042. if (getDocument().isEncryptionActive()) {
  1043. getDocument().applyEncryption(embeddedFont);
  1044. } else {
  1045. embeddedFont.getFilterList().addFilter("ascii-85");
  1046. }*/
  1047. return embeddedFont;
  1048. } finally {
  1049. in.close();
  1050. }
  1051. }
  1052. } catch (IOException ioe) {
  1053. getDocument().getLogger().error(
  1054. "Failed to embed font [" + desc + "] "
  1055. + desc.getFontName(), ioe);
  1056. return (PDFStream) null;
  1057. }
  1058. }
  1059. /* ========================= streams =================================== */
  1060. /**
  1061. * Make a stream object
  1062. *
  1063. * @param type the type of stream to be created
  1064. * @param add if true then the stream will be added immediately
  1065. * @return the stream object created
  1066. */
  1067. public PDFStream makeStream(String type, boolean add) {
  1068. // create a PDFStream with the next object number
  1069. // and add it to the list of objects
  1070. PDFStream obj = new PDFStream();
  1071. obj.setDocument(getDocument());
  1072. obj.getFilterList().addDefaultFilters(
  1073. getDocument().getFilterMap(),
  1074. type);
  1075. if (add) {
  1076. getDocument().registerObject(obj);
  1077. }
  1078. //getDocument().applyEncryption(obj);
  1079. return obj;
  1080. }
  1081. /**
  1082. * Create a PDFICCStream
  1083. * @see PDFXObject
  1084. * @see org.apache.fop.image.JpegImage
  1085. * @see org.apache.fop.pdf.PDFColorSpace
  1086. * @return the new PDF ICC stream object
  1087. */
  1088. public PDFICCStream makePDFICCStream() {
  1089. PDFICCStream iccStream = new PDFICCStream();
  1090. iccStream.getFilterList().addDefaultFilters(
  1091. getDocument().getFilterMap(),
  1092. PDFFilterList.CONTENT_FILTER);
  1093. getDocument().registerObject(iccStream);
  1094. //getDocument().applyEncryption(iccStream);
  1095. return iccStream;
  1096. }
  1097. /* ========================= misc. objects ============================= */
  1098. /**
  1099. * make an Array object (ex. Widths array for a font)
  1100. *
  1101. * @param values the int array values
  1102. * @return the PDF Array with the int values
  1103. */
  1104. public PDFArray makeArray(int[] values) {
  1105. PDFArray array = new PDFArray(values);
  1106. getDocument().registerObject(array);
  1107. return array;
  1108. }
  1109. /**
  1110. * make an ExtGState for extra graphics options
  1111. * This tries to find a GState that will setup the correct values
  1112. * for the current context. If there is no suitable GState it will
  1113. * create a new one.
  1114. *
  1115. * @param settings the settings required by the caller
  1116. * @param current the current GState of the current PDF context
  1117. * @return a PDF GState, either an existing GState or a new one
  1118. */
  1119. public PDFGState makeGState(Map settings, PDFGState current) {
  1120. // try to locate a gstate that has all the settings
  1121. // or will inherit from the current gstate
  1122. // compare "DEFAULT + settings" with "current + each gstate"
  1123. PDFGState wanted = new PDFGState();
  1124. wanted.addValues(PDFGState.DEFAULT);
  1125. wanted.addValues(settings);
  1126. PDFGState existing = getDocument().findGState(wanted, current);
  1127. if (existing != null) {
  1128. return existing;
  1129. }
  1130. PDFGState gstate = new PDFGState();
  1131. gstate.addValues(settings);
  1132. getDocument().registerObject(gstate);
  1133. return gstate;
  1134. }
  1135. /**
  1136. * Make an annotation list object
  1137. *
  1138. * @return the annotation list object created
  1139. */
  1140. public PDFAnnotList makeAnnotList() {
  1141. PDFAnnotList obj = new PDFAnnotList();
  1142. getDocument().assignObjectNumber(obj);
  1143. return obj;
  1144. }
  1145. }