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.

PDFDocument.java 48KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304
  1. /*
  2. * $Id$
  3. * Copyright (C) 2001 The Apache Software Foundation. All rights reserved.
  4. * For details on use and redistribution please refer to the
  5. * LICENSE file included with these sources.
  6. */
  7. /* image support modified from work of BoBoGi */
  8. /* font support based on work by Takayuki Takeuchi */
  9. package org.apache.fop.pdf;
  10. // images are the one place that FOP classes outside this package get
  11. // referenced and I'd rather not do it
  12. import org.apache.fop.image.FopImage;
  13. import org.apache.fop.layout.LinkSet;
  14. import org.apache.fop.datatypes.ColorSpace;
  15. import org.apache.fop.render.pdf.CIDFont;
  16. import org.apache.fop.render.pdf.fonts.LazyFont;
  17. import org.apache.fop.datatypes.IDReferences;
  18. import org.apache.fop.layout.Page;
  19. import org.apache.fop.layout.FontMetric;
  20. import org.apache.fop.layout.FontDescriptor;
  21. // Java
  22. import java.io.IOException;
  23. import java.io.OutputStream;
  24. import java.util.Vector;
  25. import java.util.Hashtable;
  26. import java.util.Enumeration;
  27. import java.awt.Rectangle;
  28. /**
  29. * class representing a PDF document.
  30. *
  31. * The document is built up by calling various methods and then finally
  32. * output to given filehandle using output method.
  33. *
  34. * A PDF document consists of a series of numbered objects preceded by a
  35. * header and followed by an xref table and trailer. The xref table
  36. * allows for quick access to objects by listing their character
  37. * positions within the document. For this reason the PDF document must
  38. * keep track of the character position of each object. The document
  39. * also keeps direct track of the /Root, /Info and /Resources objects.
  40. *
  41. * Modified by Mark Lillywhite, mark-fop@inomial.com. The changes
  42. * involve: ability to output pages one-at-a-time in a streaming
  43. * fashion (rather than storing them all for output at the end);
  44. * ability to write the /Pages object after writing the rest
  45. * of the document; ability to write to a stream and flush
  46. * the object list; enhanced trailer output; cleanups.
  47. *
  48. * Modified by lmckenzi@ca.ibm.com
  49. * Sometimes IDs are created, but not validated. This tracks
  50. * the difference.
  51. */
  52. public class PDFDocument {
  53. private static final Integer locationPlaceholder = new Integer(0);
  54. /**
  55. * the version of PDF supported
  56. */
  57. protected static final String pdfVersion = "1.3";
  58. /**
  59. * the current character position
  60. */
  61. protected int position = 0;
  62. /**
  63. * the character position of each object
  64. */
  65. protected Vector location = new Vector();
  66. /** List of objects to write in the trailer */
  67. private Vector trailerObjects = new Vector();
  68. /**
  69. * the counter for object numbering
  70. */
  71. protected int objectcount = 0;
  72. /**
  73. * the objects themselves
  74. */
  75. protected Vector objects = new Vector();
  76. /**
  77. * character position of xref table
  78. */
  79. protected int xref;
  80. /**
  81. * the /Root object
  82. */
  83. protected PDFRoot root;
  84. /** The root outline object */
  85. private PDFOutline outlineRoot = null;
  86. /** The /Pages object (mark-fop@inomial.com) */
  87. private PDFPages pages;
  88. /**
  89. * the /Info object
  90. */
  91. protected PDFInfo info;
  92. /**
  93. * the /Resources object
  94. */
  95. protected PDFResources resources;
  96. /**
  97. * the documents idReferences
  98. */
  99. protected IDReferences idReferences;
  100. /**
  101. * the colorspace (0=RGB, 1=CMYK)
  102. */
  103. // protected int colorspace = 0;
  104. protected ColorSpace colorspace = new ColorSpace(ColorSpace.DEVICE_RGB);
  105. /**
  106. * the counter for Pattern name numbering (e.g. 'Pattern1')
  107. */
  108. protected int patternCount = 0;
  109. /**
  110. * the counter for Shading name numbering
  111. */
  112. protected int shadingCount = 0;
  113. /**
  114. * the counter for XObject numbering
  115. */
  116. protected int xObjectCount = 0;
  117. /**
  118. * the XObjects
  119. */
  120. protected Vector xObjects = new Vector();
  121. /**
  122. * the XObjects Map.
  123. * Should be modified (works only for image subtype)
  124. */
  125. protected Hashtable xObjectsMap = new Hashtable();
  126. /**
  127. * the objects themselves
  128. */
  129. protected Vector pendingLinks = null;
  130. /**
  131. * creates an empty PDF document <p>
  132. *
  133. * The constructor creates a /Root and /Pages object to
  134. * track the document but does not write these objects until
  135. * the trailer is written. Note that the object ID of the
  136. * pages object is determined now, and the xref table is
  137. * updated later. This allows Pages to refer to their
  138. * Parent before we write it out. This took me a long
  139. * time to work out, and is so obvious now. Sigh.
  140. * mark-fop@inomial.com. Maybe I should do a PDF course.
  141. */
  142. public PDFDocument() {
  143. /* create the /Root, /Info and /Resources objects */
  144. this.pages = makePages();
  145. // Create the Root object
  146. this.root = makeRoot(pages);
  147. // Create the Resources object
  148. this.resources = makeResources();
  149. // Make the /Info record
  150. this.info = makeInfo();
  151. }
  152. /**
  153. * set the producer of the document
  154. *
  155. * @param producer string indicating application producing the PDF
  156. */
  157. public void setProducer(String producer) {
  158. this.info.setProducer(producer);
  159. }
  160. /**
  161. * Make a /Catalog (Root) object. This object is written in
  162. * the trailer.
  163. */
  164. public PDFRoot makeRoot(PDFPages pages) {
  165. /*
  166. * Make a /Pages object. This object is written in the trailer.
  167. */
  168. PDFRoot pdfRoot = new PDFRoot(++this.objectcount, pages);
  169. addTrailerObject(pdfRoot);
  170. return pdfRoot;
  171. }
  172. /**
  173. * Make a /Pages object. This object is written in the trailer.
  174. */
  175. public PDFPages makePages() {
  176. PDFPages pdfPages = new PDFPages(++this.objectcount);
  177. addTrailerObject(pdfPages);
  178. return pdfPages;
  179. }
  180. /**
  181. * Make a /Resources object. This object is written in the trailer.
  182. */
  183. public PDFResources makeResources() {
  184. PDFResources pdfResources = new PDFResources(++this.objectcount);
  185. addTrailerObject(pdfResources);
  186. return pdfResources;
  187. }
  188. /**
  189. * make an /Info object
  190. *
  191. * @param producer string indicating application producing the PDF
  192. * @return the created /Info object
  193. */
  194. protected PDFInfo makeInfo() {
  195. /*
  196. * create a PDFInfo with the next object number and add to
  197. * list of objects
  198. */
  199. PDFInfo pdfInfo = new PDFInfo(++this.objectcount);
  200. // set the default producer
  201. pdfInfo.setProducer(org.apache.fop.apps.Version.getVersion());
  202. this.objects.addElement(pdfInfo);
  203. return pdfInfo;
  204. }
  205. /**
  206. * Make a Type 0 sampled function
  207. *
  208. * @param theDomain Vector objects of Double objects.
  209. * This is the domain of the function.
  210. * See page 264 of the PDF 1.3 Spec.
  211. * @param theRange Vector objects of Double objects.
  212. * This is the Range of the function.
  213. * See page 264 of the PDF 1.3 Spec.
  214. * @param theSize A Vector object of Integer objects.
  215. * This is the number of samples in each input dimension.
  216. * I can't imagine there being more or less than two input dimensions,
  217. * so maybe this should be an array of length 2.
  218. *
  219. * See page 265 of the PDF 1.3 Spec.
  220. * @param theBitsPerSample An int specifying the number of bits user to represent each sample value.
  221. * Limited to 1,2,4,8,12,16,24 or 32.
  222. * See page 265 of the 1.3 PDF Spec.
  223. * @param theOrder The order of interpolation between samples. Default is 1 (one). Limited
  224. * to 1 (one) or 3, which means linear or cubic-spline interpolation.
  225. *
  226. * This attribute is optional.
  227. *
  228. * See page 265 in the PDF 1.3 spec.
  229. * @param theEncode Vector objects of Double objects.
  230. * This is the linear mapping of input values intop the domain
  231. * of the function's sample table. Default is hard to represent in
  232. * ascii, but basically [0 (Size0 1) 0 (Size1 1)...].
  233. * This attribute is optional.
  234. *
  235. * See page 265 in the PDF 1.3 spec.
  236. * @param theDecode Vector objects of Double objects.
  237. * This is a linear mapping of sample values into the range.
  238. * The default is just the range.
  239. *
  240. * This attribute is optional.
  241. * Read about it on page 265 of the PDF 1.3 spec.
  242. * @param theFunctionDataStream The sample values that specify the function are provided in a stream.
  243. *
  244. * This is optional, but is almost always used.
  245. *
  246. * Page 265 of the PDF 1.3 spec has more.
  247. * @param theFilter This is a vector of String objects which are the various filters that
  248. * have are to be applied to the stream to make sense of it. Order matters,
  249. * so watch out.
  250. *
  251. * This is not documented in the Function section of the PDF 1.3 spec,
  252. * it was deduced from samples that this is sometimes used, even if we may never
  253. * use it in FOP. It is added for completeness sake.
  254. * @param theNumber The object number of this PDF object.
  255. * @param theFunctionType This is the type of function (0,2,3, or 4).
  256. * It should be 0 as this is the constructor for sampled functions.
  257. */
  258. public PDFFunction makeFunction(int theFunctionType, Vector theDomain,
  259. Vector theRange, Vector theSize,
  260. int theBitsPerSample, int theOrder,
  261. Vector theEncode, Vector theDecode,
  262. StringBuffer theFunctionDataStream,
  263. Vector theFilter) { // Type 0 function
  264. PDFFunction function = new PDFFunction(++this.objectcount,
  265. theFunctionType, theDomain,
  266. theRange, theSize,
  267. theBitsPerSample, theOrder,
  268. theEncode, theDecode,
  269. theFunctionDataStream,
  270. theFilter);
  271. this.objects.addElement(function);
  272. return (function);
  273. }
  274. /**
  275. * make a type Exponential interpolation function
  276. * (for shading usually)
  277. *
  278. * @param theDomain Vector objects of Double objects.
  279. * This is the domain of the function.
  280. * See page 264 of the PDF 1.3 Spec.
  281. * @param theRange Vector of Doubles that is the Range of the function.
  282. * See page 264 of the PDF 1.3 Spec.
  283. * @param theCZero This is a vector of Double objects which defines the function result
  284. * when x=0.
  285. *
  286. * This attribute is optional.
  287. * It's described on page 268 of the PDF 1.3 spec.
  288. * @param theCOne This is a vector of Double objects which defines the function result
  289. * when x=1.
  290. *
  291. * This attribute is optional.
  292. * It's described on page 268 of the PDF 1.3 spec.
  293. * @param theInterpolationExponentN This is the inerpolation exponent.
  294. *
  295. * This attribute is required.
  296. * PDF Spec page 268
  297. * @param theFunctionType The type of the function, which should be 2.
  298. */
  299. public PDFFunction makeFunction(int theFunctionType, Vector theDomain,
  300. Vector theRange, Vector theCZero,
  301. Vector theCOne,
  302. double theInterpolationExponentN) { // type 2
  303. PDFFunction function = new PDFFunction(++this.objectcount,
  304. theFunctionType, theDomain,
  305. theRange, theCZero, theCOne,
  306. theInterpolationExponentN);
  307. this.objects.addElement(function);
  308. return (function);
  309. }
  310. /**
  311. * Make a Type 3 Stitching function
  312. *
  313. * @param theDomain Vector objects of Double objects.
  314. * This is the domain of the function.
  315. * See page 264 of the PDF 1.3 Spec.
  316. * @param theRange Vector objects of Double objects.
  317. * This is the Range of the function.
  318. * See page 264 of the PDF 1.3 Spec.
  319. * @param theFunctions A Vector of the PDFFunction objects that the stitching function stitches.
  320. *
  321. * This attributed is required.
  322. * It is described on page 269 of the PDF spec.
  323. * @param theBounds This is a vector of Doubles representing the numbers that,
  324. * in conjunction with Domain define the intervals to which each function from
  325. * the 'functions' object applies. It must be in order of increasing magnitude,
  326. * and each must be within Domain.
  327. *
  328. * It basically sets how much of the gradient each function handles.
  329. *
  330. * This attributed is required.
  331. * It's described on page 269 of the PDF 1.3 spec.
  332. * @param theEncode Vector objects of Double objects.
  333. * This is the linear mapping of input values intop the domain
  334. * of the function's sample table. Default is hard to represent in
  335. * ascii, but basically [0 (Size0 1) 0 (Size1 1)...].
  336. * This attribute is required.
  337. *
  338. * See page 270 in the PDF 1.3 spec.
  339. * @param theFunctionType This is the function type. It should be 3,
  340. * for a stitching function.
  341. */
  342. public PDFFunction makeFunction(int theFunctionType, Vector theDomain,
  343. Vector theRange, Vector theFunctions,
  344. Vector theBounds,
  345. Vector theEncode) { // Type 3
  346. PDFFunction function = new PDFFunction(++this.objectcount,
  347. theFunctionType, theDomain,
  348. theRange, theFunctions,
  349. theBounds, theEncode);
  350. this.objects.addElement(function);
  351. return (function);
  352. }
  353. /**
  354. * make a postscript calculator function
  355. *
  356. * @param theNumber
  357. * @param theFunctionType
  358. * @param theDomain
  359. * @param theRange
  360. * @param theFunctionDataStream
  361. */
  362. public PDFFunction makeFunction(int theNumber, int theFunctionType,
  363. Vector theDomain, Vector theRange,
  364. StringBuffer theFunctionDataStream) { // Type 4
  365. PDFFunction function = new PDFFunction(++this.objectcount,
  366. theFunctionType, theDomain,
  367. theRange,
  368. theFunctionDataStream);
  369. this.objects.addElement(function);
  370. return (function);
  371. }
  372. /**
  373. * make a function based shading object
  374. *
  375. * @param theShadingType The type of shading object, which should be 1 for function
  376. * based shading.
  377. * @param theColorSpace The colorspace is 'DeviceRGB' or something similar.
  378. * @param theBackground An array of color components appropriate to the
  379. * colorspace key specifying a single color value.
  380. * This key is used by the f operator buy ignored by the sh operator.
  381. * @param theBBox Vector of double's representing a rectangle
  382. * in the coordinate space that is current at the
  383. * time of shading is imaged. Temporary clipping
  384. * boundary.
  385. * @param theAntiAlias Whether or not to anti-alias.
  386. * @param theDomain Optional vector of Doubles specifying the domain.
  387. * @param theMatrix Vector of Doubles specifying the matrix.
  388. * If it's a pattern, then the matrix maps it to pattern space.
  389. * If it's a shading, then it maps it to current user space.
  390. * It's optional, the default is the identity matrix
  391. * @param theFunction The PDF Function that maps an (x,y) location to a color
  392. */
  393. public PDFShading makeShading(int theShadingType,
  394. ColorSpace theColorSpace,
  395. Vector theBackground, Vector theBBox,
  396. boolean theAntiAlias, Vector theDomain,
  397. Vector theMatrix,
  398. PDFFunction theFunction) { // make Shading of Type 1
  399. String theShadingName = new String("Sh" + (++this.shadingCount));
  400. PDFShading shading = new PDFShading(++this.objectcount,
  401. theShadingName, theShadingType,
  402. theColorSpace, theBackground,
  403. theBBox, theAntiAlias, theDomain,
  404. theMatrix, theFunction);
  405. this.objects.addElement(shading);
  406. // add this shading to resources
  407. this.resources.addShading(shading);
  408. return (shading);
  409. }
  410. /**
  411. * Make an axial or radial shading object.
  412. *
  413. * @param theShadingType 2 or 3 for axial or radial shading
  414. * @param theColorSpace "DeviceRGB" or similar.
  415. * @param theBackground theBackground An array of color components appropriate to the
  416. * colorspace key specifying a single color value.
  417. * This key is used by the f operator buy ignored by the sh operator.
  418. * @param theBBox Vector of double's representing a rectangle
  419. * in the coordinate space that is current at the
  420. * time of shading is imaged. Temporary clipping
  421. * boundary.
  422. * @param theAntiAlias Default is false
  423. * @param theCoords Vector of four (type 2) or 6 (type 3) Double
  424. * @param theDomain Vector of Doubles specifying the domain
  425. * @param theFunction the Stitching (PDFfunction type 3) function, even if it's stitching a single function
  426. * @param theExtend Vector of Booleans of whether to extend teh start and end colors past the start and end points
  427. * The default is [false, false]
  428. */
  429. public PDFShading makeShading(int theShadingType,
  430. ColorSpace theColorSpace,
  431. Vector theBackground, Vector theBBox,
  432. boolean theAntiAlias, Vector theCoords,
  433. Vector theDomain, PDFFunction theFunction,
  434. Vector theExtend) { // make Shading of Type 2 or 3
  435. String theShadingName = new String("Sh" + (++this.shadingCount));
  436. PDFShading shading = new PDFShading(++this.objectcount,
  437. theShadingName, theShadingType,
  438. theColorSpace, theBackground,
  439. theBBox, theAntiAlias, theCoords,
  440. theDomain, theFunction,
  441. theExtend);
  442. this.resources.addShading(shading);
  443. this.objects.addElement(shading);
  444. return (shading);
  445. }
  446. /**
  447. * Make a free-form gouraud shaded triangle mesh, coons patch mesh, or tensor patch mesh
  448. * shading object
  449. *
  450. * @param theShadingType 4, 6, or 7 depending on whether it's
  451. * Free-form gouraud-shaded triangle meshes, coons patch meshes,
  452. * or tensor product patch meshes, respectively.
  453. * @param theColorSpace "DeviceRGB" or similar.
  454. * @param theBackground theBackground An array of color components appropriate to the
  455. * colorspace key specifying a single color value.
  456. * This key is used by the f operator buy ignored by the sh operator.
  457. * @param theBBox Vector of double's representing a rectangle
  458. * in the coordinate space that is current at the
  459. * time of shading is imaged. Temporary clipping
  460. * boundary.
  461. * @param theAntiAlias Default is false
  462. * @param theBitsPerCoordinate 1,2,4,8,12,16,24 or 32.
  463. * @param theBitsPerComponent 1,2,4,8,12, and 16
  464. * @param theBitsPerFlag 2,4,8.
  465. * @param theDecode Vector of Doubles see PDF 1.3 spec pages 303 to 312.
  466. * @param theFunction the PDFFunction
  467. */
  468. public PDFShading makeShading(int theShadingType,
  469. ColorSpace theColorSpace,
  470. Vector theBackground, Vector theBBox,
  471. boolean theAntiAlias,
  472. int theBitsPerCoordinate,
  473. int theBitsPerComponent,
  474. int theBitsPerFlag, Vector theDecode,
  475. PDFFunction theFunction) { // make Shading of type 4,6 or 7
  476. String theShadingName = new String("Sh" + (++this.shadingCount));
  477. PDFShading shading = new PDFShading(++this.objectcount,
  478. theShadingName, theShadingType,
  479. theColorSpace, theBackground,
  480. theBBox, theAntiAlias,
  481. theBitsPerCoordinate,
  482. theBitsPerComponent,
  483. theBitsPerFlag, theDecode,
  484. theFunction);
  485. this.resources.addShading(shading);
  486. this.objects.addElement(shading);
  487. return (shading);
  488. }
  489. /**
  490. * make a Lattice-Form Gouraud mesh shading object
  491. *
  492. * @param theShadingType 5 for lattice-Form Gouraud shaded-triangle mesh
  493. * without spaces. "Shading1" or "Sh1" are good examples.
  494. * @param theColorSpace "DeviceRGB" or similar.
  495. * @param theBackground theBackground An array of color components appropriate to the
  496. * colorspace key specifying a single color value.
  497. * This key is used by the f operator buy ignored by the sh operator.
  498. * @param theBBox Vector of double's representing a rectangle
  499. * in the coordinate space that is current at the
  500. * time of shading is imaged. Temporary clipping
  501. * boundary.
  502. * @param theAntiAlias Default is false
  503. * @param theBitsPerCoordinate 1,2,4,8,12,16, 24, or 32
  504. * @param theBitsPerComponent 1,2,4,8,12,24,32
  505. * @param theDecode Vector of Doubles. See page 305 in PDF 1.3 spec.
  506. * @param theVerticesPerRow number of vertices in each "row" of the lattice.
  507. * @param theFunction The PDFFunction that's mapped on to this shape
  508. */
  509. public PDFShading makeShading(int theShadingType,
  510. ColorSpace theColorSpace,
  511. Vector theBackground, Vector theBBox,
  512. boolean theAntiAlias,
  513. int theBitsPerCoordinate,
  514. int theBitsPerComponent, Vector theDecode,
  515. int theVerticesPerRow,
  516. PDFFunction theFunction) { // make shading of Type 5
  517. String theShadingName = new String("Sh" + (++this.shadingCount));
  518. PDFShading shading = new PDFShading(++this.objectcount,
  519. theShadingName, theShadingType,
  520. theColorSpace, theBackground,
  521. theBBox, theAntiAlias,
  522. theBitsPerCoordinate,
  523. theBitsPerComponent, theDecode,
  524. theVerticesPerRow, theFunction);
  525. this.resources.addShading(shading);
  526. this.objects.addElement(shading);
  527. return (shading);
  528. }
  529. /**
  530. * Make a tiling pattern
  531. *
  532. * @param thePatternType the type of pattern, which is 1 for tiling.
  533. * @param theResources the resources associated with this pattern
  534. * @param thePaintType 1 or 2, colored or uncolored.
  535. * @param theTilingType 1, 2, or 3, constant spacing, no distortion, or faster tiling
  536. * @param theBBox Vector of Doubles: The pattern cell bounding box
  537. * @param theXStep horizontal spacing
  538. * @param theYStep vertical spacing
  539. * @param theMatrix Optional Vector of Doubles transformation matrix
  540. * @param theXUID Optional vector of Integers that uniquely identify the pattern
  541. * @param thePatternDataStream The stream of pattern data to be tiled.
  542. */
  543. public PDFPattern makePattern(int thePatternType, // 1
  544. PDFResources theResources, int thePaintType, int theTilingType,
  545. Vector theBBox, double theXStep, double theYStep, Vector theMatrix,
  546. Vector theXUID, StringBuffer thePatternDataStream) {
  547. String thePatternName = new String("Pa" + (++this.patternCount));
  548. // int theNumber, String thePatternName,
  549. // PDFResources theResources
  550. PDFPattern pattern = new PDFPattern(++this.objectcount,
  551. thePatternName, theResources, 1,
  552. thePaintType, theTilingType,
  553. theBBox, theXStep, theYStep,
  554. theMatrix, theXUID,
  555. thePatternDataStream);
  556. this.resources.addPattern(pattern);
  557. this.objects.addElement(pattern);
  558. return (pattern);
  559. }
  560. /**
  561. * Make a smooth shading pattern
  562. *
  563. * @param thePatternType the type of the pattern, which is 2, smooth shading
  564. * @param theShading the PDF Shading object that comprises this pattern
  565. * @param theXUID optional:the extended unique Identifier if used.
  566. * @param theExtGState optional: the extended graphics state, if used.
  567. * @param theMatrix Optional:Vector of Doubles that specify the matrix.
  568. */
  569. public PDFPattern makePattern(int thePatternType, PDFShading theShading,
  570. Vector theXUID, StringBuffer theExtGState,
  571. Vector theMatrix) {
  572. String thePatternName = new String("Pa" + (++this.patternCount));
  573. PDFPattern pattern = new PDFPattern(++this.objectcount,
  574. thePatternName, 2, theShading,
  575. theXUID, theExtGState, theMatrix);
  576. this.resources.addPattern(pattern);
  577. this.objects.addElement(pattern);
  578. return (pattern);
  579. }
  580. public int getColorSpace() {
  581. return (this.colorspace.getColorSpace());
  582. }
  583. public void setColorSpace(int theColorspace) {
  584. this.colorspace.setColorSpace(theColorspace);
  585. return;
  586. }
  587. public PDFPattern createGradient(boolean radial,
  588. ColorSpace theColorspace,
  589. Vector theColors, Vector theBounds,
  590. Vector theCoords) {
  591. PDFShading myShad;
  592. PDFFunction myfunky;
  593. PDFFunction myfunc;
  594. Vector theCzero;
  595. Vector theCone;
  596. PDFPattern myPattern;
  597. ColorSpace theColorSpace;
  598. double interpolation = (double)1.000;
  599. Vector theFunctions = new Vector();
  600. int currentPosition;
  601. int lastPosition = theColors.size() - 1;
  602. // if 5 elements, the penultimate element is 3.
  603. // do not go beyond that, because you always need
  604. // to have a next color when creating the function.
  605. for (currentPosition = 0; currentPosition < lastPosition;
  606. currentPosition++) { // for every consecutive color pair
  607. PDFColor currentColor =
  608. (PDFColor)theColors.elementAt(currentPosition);
  609. PDFColor nextColor = (PDFColor)theColors.elementAt(currentPosition
  610. + 1);
  611. // colorspace must be consistant
  612. if (this.colorspace.getColorSpace()
  613. != currentColor.getColorSpace())
  614. currentColor.setColorSpace(this.colorspace.getColorSpace());
  615. if (this.colorspace.getColorSpace() != nextColor.getColorSpace())
  616. nextColor.setColorSpace(this.colorspace.getColorSpace());
  617. theCzero = currentColor.getVector();
  618. theCone = nextColor.getVector();
  619. myfunc = this.makeFunction(2, null, null, theCzero, theCone,
  620. interpolation);
  621. theFunctions.addElement(myfunc);
  622. } // end of for every consecutive color pair
  623. myfunky = this.makeFunction(3, null, null, theFunctions, theBounds,
  624. null);
  625. if (radial) {
  626. if (theCoords.size() == 6) {
  627. myShad = this.makeShading(3, this.colorspace, null, null,
  628. false, theCoords, null, myfunky,
  629. null);
  630. } else { // if the center x, center y, and radius specifiy
  631. // the gradient, then assume the same center x, center y,
  632. // and radius of zero for the other necessary component
  633. Vector newCoords = new Vector();
  634. newCoords.addElement(theCoords.elementAt(0));
  635. newCoords.addElement(theCoords.elementAt(1));
  636. newCoords.addElement(theCoords.elementAt(2));
  637. newCoords.addElement(theCoords.elementAt(0));
  638. newCoords.addElement(theCoords.elementAt(1));
  639. newCoords.addElement(new Double(0.0));
  640. myShad = this.makeShading(3, this.colorspace, null, null,
  641. false, newCoords, null, myfunky,
  642. null);
  643. }
  644. } else {
  645. myShad = this.makeShading(2, this.colorspace, null, null, false,
  646. theCoords, null, myfunky, null);
  647. }
  648. myPattern = this.makePattern(2, myShad, null, null, null);
  649. return (myPattern);
  650. }
  651. /**
  652. * make a /Encoding object
  653. *
  654. * @param encodingName character encoding scheme name
  655. * @return the created /Encoding object
  656. */
  657. public PDFEncoding makeEncoding(String encodingName) {
  658. /*
  659. * create a PDFEncoding with the next object number and add to the
  660. * list of objects
  661. */
  662. PDFEncoding encoding = new PDFEncoding(++this.objectcount,
  663. encodingName);
  664. this.objects.addElement(encoding);
  665. return encoding;
  666. }
  667. /**
  668. * make a Type1 /Font object
  669. *
  670. * @param fontname internal name to use for this font (eg "F1")
  671. * @param basefont name of the base font (eg "Helvetica")
  672. * @param encoding character encoding scheme used by the font
  673. * @param metrics additional information about the font
  674. * @param descriptor additional information about the font
  675. * @return the created /Font object
  676. */
  677. public PDFFont makeFont(String fontname, String basefont,
  678. String encoding, FontMetric metrics,
  679. FontDescriptor descriptor) {
  680. /*
  681. * create a PDFFont with the next object number and add to the
  682. * list of objects
  683. */
  684. if (descriptor == null) {
  685. PDFFont font = new PDFFont(++this.objectcount, fontname,
  686. PDFFont.TYPE1, basefont, encoding);
  687. this.objects.addElement(font);
  688. return font;
  689. } else {
  690. byte subtype = PDFFont.TYPE1;
  691. if (metrics instanceof org.apache.fop.render.pdf.Font)
  692. subtype =
  693. ((org.apache.fop.render.pdf.Font)metrics).getSubType();
  694. PDFFontDescriptor pdfdesc = makeFontDescriptor(descriptor,
  695. subtype);
  696. PDFFontNonBase14 font = null;
  697. if (subtype == PDFFont.TYPE0) {
  698. /*
  699. * Temporary commented out - customized CMaps
  700. * isn't needed until /ToUnicode support is added
  701. * PDFCMap cmap = new PDFCMap(++this.objectcount,
  702. * "fop-ucs-H",
  703. * new PDFCIDSystemInfo("Adobe",
  704. * "Identity",
  705. * 0));
  706. * cmap.addContents();
  707. * this.objects.addElement(cmap);
  708. */
  709. font =
  710. (PDFFontNonBase14)PDFFont.createFont(++this.objectcount,
  711. fontname, subtype,
  712. basefont,
  713. "Identity-H");
  714. } else {
  715. font =
  716. (PDFFontNonBase14)PDFFont.createFont(++this.objectcount,
  717. fontname, subtype,
  718. basefont, encoding);
  719. }
  720. this.objects.addElement(font);
  721. font.setDescriptor(pdfdesc);
  722. if (subtype == PDFFont.TYPE0) {
  723. CIDFont cidMetrics;
  724. if(metrics instanceof LazyFont){
  725. cidMetrics = (CIDFont) ((LazyFont) metrics).getRealFont();
  726. }else{
  727. cidMetrics = (CIDFont)metrics;
  728. }
  729. PDFCIDSystemInfo sysInfo =
  730. new PDFCIDSystemInfo(cidMetrics.getRegistry(),
  731. cidMetrics.getOrdering(),
  732. cidMetrics.getSupplement());
  733. PDFCIDFont cidFont =
  734. new PDFCIDFont(++this.objectcount, basefont,
  735. cidMetrics.getCidType(),
  736. cidMetrics.getDefaultWidth(),
  737. cidMetrics.getWidths(), sysInfo,
  738. (PDFCIDFontDescriptor)pdfdesc);
  739. this.objects.addElement(cidFont);
  740. // ((PDFFontType0)font).setCMAP(cmap);
  741. ((PDFFontType0)font).setDescendantFonts(cidFont);
  742. } else {
  743. font.setWidthMetrics(metrics.getFirstChar(),
  744. metrics.getLastChar(),
  745. makeArray(metrics.getWidths(1)));
  746. }
  747. return font;
  748. }
  749. }
  750. /**
  751. * make a /FontDescriptor object
  752. */
  753. public PDFFontDescriptor makeFontDescriptor(FontDescriptor desc,
  754. byte subtype) {
  755. PDFFontDescriptor font = null;
  756. if (subtype == PDFFont.TYPE0) {
  757. // CID Font
  758. font = new PDFCIDFontDescriptor(++this.objectcount,
  759. desc.fontName(),
  760. desc.getFontBBox(),
  761. // desc.getAscender(),
  762. // desc.getDescender(),
  763. desc.getCapHeight(), desc.getFlags(),
  764. // new PDFRectangle(desc.getFontBBox()),
  765. desc.getItalicAngle(), desc.getStemV(), null); // desc.getLang(),
  766. // null);//desc.getPanose());
  767. }
  768. else {
  769. // Create normal FontDescriptor
  770. font = new PDFFontDescriptor(++this.objectcount, desc.fontName(),
  771. desc.getAscender(),
  772. desc.getDescender(),
  773. desc.getCapHeight(),
  774. desc.getFlags(),
  775. new PDFRectangle(desc.getFontBBox()),
  776. desc.getStemV(),
  777. desc.getItalicAngle());
  778. }
  779. this.objects.addElement(font);
  780. // Check if the font is embeddable
  781. if (desc.isEmbeddable()) {
  782. PDFStream stream = desc.getFontFile(this.objectcount + 1);
  783. if (stream != null) {
  784. this.objectcount++;
  785. font.setFontFile(desc.getSubType(), stream);
  786. this.objects.addElement(stream);
  787. }
  788. }
  789. return font;
  790. }
  791. /**
  792. * make an Array object (ex. Widths array for a font)
  793. */
  794. public PDFArray makeArray(int[] values) {
  795. PDFArray array = new PDFArray(++this.objectcount, values);
  796. this.objects.addElement(array);
  797. return array;
  798. }
  799. public int addImage(FopImage img) {
  800. // check if already created
  801. String url = img.getURL();
  802. PDFXObject xObject = (PDFXObject)this.xObjectsMap.get(url);
  803. if (xObject != null)
  804. return xObject.getXNumber();
  805. // else, create a new one
  806. xObject = new PDFXObject(++this.objectcount, ++this.xObjectCount,
  807. img);
  808. this.objects.addElement(xObject);
  809. this.xObjects.addElement(xObject);
  810. this.xObjectsMap.put(url, xObject);
  811. return xObjectCount;
  812. }
  813. /**
  814. * make a /Page object
  815. *
  816. * @param resources resources object to use
  817. * @param contents stream object with content
  818. * @param pagewidth width of the page in points
  819. * @param pageheight height of the page in points
  820. *
  821. * @return the created /Page object
  822. */
  823. public PDFPage makePage(PDFResources resources, PDFStream contents,
  824. int pagewidth, int pageheight) {
  825. /*
  826. * create a PDFPage with the next object number, the given
  827. * resources, contents and dimensions
  828. */
  829. PDFPage page = new PDFPage(++this.objectcount, resources, contents,
  830. pagewidth, pageheight);
  831. if(pendingLinks != null) {
  832. for(Enumeration e = pendingLinks.elements(); e.hasMoreElements(); ) {
  833. PendingLink pl = (PendingLink)e.nextElement();
  834. PDFGoTo gt = new PDFGoTo(++this.objectcount,
  835. page.referencePDF());
  836. gt.setDestination(pl.dest);
  837. addTrailerObject(gt);
  838. PDFInternalLink internalLink =
  839. new PDFInternalLink(gt.referencePDF());
  840. pl.link.setAction(internalLink);
  841. }
  842. pendingLinks = null;
  843. }
  844. /*
  845. if (currentPage != null) {
  846. Enumeration enum = currentPage.getIDList().elements();
  847. while (enum.hasMoreElements()) {
  848. String id = enum.nextElement().toString();
  849. idReferences.setInternalGoToPageReference(id,
  850. page.referencePDF());
  851. }
  852. }
  853. */
  854. /* add it to the list of objects */
  855. this.objects.addElement(page);
  856. /* add the page to the Root */
  857. this.root.addPage(page);
  858. return page;
  859. }
  860. /**
  861. * make a link object
  862. *
  863. * @param rect the clickable rectangle
  864. * @param destination the destination file
  865. * @param linkType the link type
  866. * @return the PDFLink object created
  867. */
  868. public PDFLink makeLink(Rectangle rect, String destination,
  869. int linkType) {
  870. PDFLink linkObject;
  871. PDFAction action;
  872. PDFLink link = new PDFLink(++this.objectcount, rect);
  873. this.objects.addElement(link);
  874. if (linkType == LinkSet.EXTERNAL) {
  875. // check destination
  876. if (destination.endsWith(".pdf")) { // FileSpec
  877. PDFFileSpec fileSpec = new PDFFileSpec(++this.objectcount,
  878. destination);
  879. this.objects.addElement(fileSpec);
  880. action = new PDFGoToRemote(++this.objectcount, fileSpec);
  881. this.objects.addElement(action);
  882. link.setAction(action);
  883. } else { // URI
  884. PDFUri uri = new PDFUri(destination);
  885. link.setAction(uri);
  886. }
  887. } else { // linkType is internal
  888. String goToReference = getGoToReference(destination);
  889. PDFInternalLink internalLink = new PDFInternalLink(goToReference);
  890. link.setAction(internalLink);
  891. }
  892. return link;
  893. }
  894. private String getGoToReference(String destination) {
  895. String goToReference;
  896. if (idReferences.doesIDExist(destination)) {
  897. if (idReferences.doesGoToReferenceExist(destination)) {
  898. goToReference =
  899. idReferences.getInternalLinkGoToReference(destination);
  900. } else { // assign Internal Link GoTo object
  901. goToReference =
  902. idReferences.createInternalLinkGoTo(destination,
  903. ++this.objectcount);
  904. addTrailerObject(idReferences.getPDFGoTo(destination));
  905. }
  906. } else { // id was not found, so create it
  907. //next line by lmckenzi@ca.ibm.com
  908. //solves when IDNode made before IDReferences.createID called
  909. //idReferences.createNewId(destination);
  910. idReferences.createUnvalidatedID(destination);
  911. idReferences.addToIdValidationList(destination);
  912. goToReference = idReferences.createInternalLinkGoTo(destination,
  913. ++this.objectcount);
  914. addTrailerObject(idReferences.getPDFGoTo(destination));
  915. }
  916. return goToReference;
  917. }
  918. public void addTrailerObject(PDFObject object) {
  919. this.trailerObjects.addElement(object);
  920. }
  921. class PendingLink {
  922. PDFLink link;
  923. String dest;
  924. }
  925. public PDFLink makeLinkCurrentPage(Rectangle rect, String dest) {
  926. PDFLink link = new PDFLink(++this.objectcount, rect);
  927. this.objects.addElement(link);
  928. PendingLink pl = new PendingLink();
  929. pl.link = link;
  930. pl.dest = dest;
  931. if(pendingLinks == null) {
  932. pendingLinks = new Vector();
  933. }
  934. pendingLinks.addElement(pl);
  935. return link;
  936. }
  937. public PDFLink makeLink(Rectangle rect, String page, String dest) {
  938. PDFLink link = new PDFLink(++this.objectcount, rect);
  939. this.objects.addElement(link);
  940. PDFGoTo gt = new PDFGoTo(++this.objectcount, page);
  941. gt.setDestination(dest);
  942. addTrailerObject(gt);
  943. PDFInternalLink internalLink = new PDFInternalLink(gt.referencePDF());
  944. link.setAction(internalLink);
  945. return link;
  946. }
  947. /**
  948. Ensure there is room in the locations xref for the number of
  949. objects that have been created.
  950. */
  951. private void prepareLocations() {
  952. while(location.size() < objectcount)
  953. location.addElement(locationPlaceholder);
  954. }
  955. /**
  956. * make a stream object
  957. *
  958. * @return the stream object created
  959. */
  960. public PDFStream makeStream() {
  961. /*
  962. * create a PDFStream with the next object number and add it
  963. *
  964. * to the list of objects
  965. */
  966. PDFStream obj = new PDFStream(++this.objectcount);
  967. obj.addDefaultFilters();
  968. this.objects.addElement(obj);
  969. return obj;
  970. }
  971. /**
  972. * make an annotation list object
  973. *
  974. * @return the annotation list object created
  975. */
  976. public PDFAnnotList makeAnnotList() {
  977. /*
  978. * create a PDFAnnotList with the next object number and add it
  979. * to the list of objects
  980. */
  981. PDFAnnotList obj = new PDFAnnotList(++this.objectcount);
  982. this.objects.addElement(obj);
  983. return obj;
  984. }
  985. /**
  986. * Get the root Outlines object. This method does not write
  987. * the outline to the PDF document, it simply creates a
  988. * reference for later.
  989. */
  990. public PDFOutline getOutlineRoot() {
  991. if(outlineRoot != null)
  992. return outlineRoot;
  993. outlineRoot = new PDFOutline(++this.objectcount, null, null);
  994. addTrailerObject(outlineRoot);
  995. root.setRootOutline(outlineRoot);
  996. return outlineRoot;
  997. }
  998. /**
  999. * Make an outline object and add it to the given outline
  1000. * @param parent parent PDFOutline object
  1001. * @param label the title for the new outline object
  1002. * @param action the PDFAction to reference
  1003. */
  1004. public PDFOutline makeOutline(PDFOutline parent, String label,
  1005. String destination) {
  1006. String goToRef = getGoToReference(destination);
  1007. PDFOutline obj = new PDFOutline(++this.objectcount, label, goToRef);
  1008. //log.debug("created new outline object");
  1009. if (parent != null) {
  1010. parent.addOutline(obj);
  1011. }
  1012. this.objects.addElement(obj);
  1013. return obj;
  1014. }
  1015. /**
  1016. * get the /Resources object for the document
  1017. *
  1018. * @return the /Resources object
  1019. */
  1020. public PDFResources getResources() {
  1021. return this.resources;
  1022. }
  1023. /**
  1024. * write the entire document out
  1025. *
  1026. * @param writer the OutputStream to output the document to
  1027. */
  1028. public void output(OutputStream stream) throws IOException {
  1029. prepareLocations();
  1030. Enumeration en = this.objects.elements();
  1031. while (en.hasMoreElements()) {
  1032. /* retrieve the object with the current number */
  1033. PDFObject object = (PDFObject)en.nextElement();
  1034. /*
  1035. * add the position of this object to the list of object
  1036. * locations
  1037. */
  1038. location.setElementAt(
  1039. new Integer(this.position),object.getNumber() - 1);
  1040. /*
  1041. * output the object and increment the character position
  1042. * by the object's length
  1043. */
  1044. this.position += object.output(stream);
  1045. }
  1046. this.objects.clear();
  1047. }
  1048. /**
  1049. * write the PDF header <P>
  1050. *
  1051. * This method must be called prior to formatting
  1052. * and outputting AreaTrees.
  1053. *
  1054. * @param stream the OutputStream to write the header to
  1055. * @return the number of bytes written
  1056. */
  1057. public void outputHeader(OutputStream stream)
  1058. throws IOException {
  1059. this.position=0;
  1060. byte[] pdf = ("%PDF-" + this.pdfVersion + "\n").getBytes();
  1061. stream.write(pdf);
  1062. this.position += pdf.length;
  1063. // output a binary comment as recommended by the PDF spec (3.4.1)
  1064. byte[] bin = {
  1065. (byte)'%', (byte)0xAA, (byte)0xAB, (byte)0xAC, (byte)0xAD,
  1066. (byte)'\n'
  1067. };
  1068. stream.write(bin);
  1069. this.position += bin.length;
  1070. this.resources.setXObjects(xObjects);
  1071. }
  1072. /**
  1073. * write the trailer
  1074. *
  1075. * @param stream the OutputStream to write the trailer to
  1076. */
  1077. public void outputTrailer(OutputStream stream)
  1078. throws IOException {
  1079. output(stream);
  1080. Enumeration e = trailerObjects.elements();
  1081. while(e.hasMoreElements()) {
  1082. PDFObject o = (PDFObject) e.nextElement();
  1083. this.location.setElementAt(
  1084. new Integer(this.position), o.getNumber() - 1);
  1085. this.position += o.output(stream);
  1086. }
  1087. /* output the xref table and increment the character position
  1088. by the table's length */
  1089. this.position += outputXref(stream);
  1090. /* construct the trailer */
  1091. String pdf =
  1092. "trailer\n" +
  1093. "<<\n" +
  1094. "/Size " + (this.objectcount + 1) + "\n" +
  1095. "/Root " + this.root.number + " " + this.root.generation + " R\n" +
  1096. "/Info " + this.info.number + " " + this.info.generation + " R\n" +
  1097. ">>\n" +
  1098. "startxref\n" +
  1099. this.xref + "\n" +
  1100. "%%EOF\n";
  1101. /* write the trailer */
  1102. stream.write(pdf.getBytes());
  1103. }
  1104. /**
  1105. * write the xref table
  1106. *
  1107. * @param stream the OutputStream to write the xref table to
  1108. * @return the number of characters written
  1109. */
  1110. private int outputXref(OutputStream stream) throws IOException {
  1111. /* remember position of xref table */
  1112. this.xref = this.position;
  1113. /* construct initial part of xref */
  1114. StringBuffer pdf = new StringBuffer("xref\n0 "
  1115. + (this.objectcount + 1)
  1116. + "\n0000000000 65535 f \n");
  1117. Enumeration en = this.location.elements();
  1118. while (en.hasMoreElements()) {
  1119. String x = en.nextElement().toString();
  1120. /* contruct xref entry for object */
  1121. String padding = "0000000000";
  1122. String loc = padding.substring(x.length()) + x;
  1123. /* append to xref table */
  1124. pdf = pdf.append(loc + " 00000 n \n");
  1125. }
  1126. /* write the xref table and return the character length */
  1127. byte[] pdfBytes = pdf.toString().getBytes();
  1128. stream.write(pdfBytes);
  1129. return pdfBytes.length;
  1130. }
  1131. public void setIDReferences(IDReferences idReferences) {
  1132. this.idReferences = idReferences;
  1133. }
  1134. }