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.

PDFGraphics2D.java 50KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421
  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. package org.apache.fop.svg;
  8. import org.apache.fop.pdf.*;
  9. import org.apache.fop.layout.*;
  10. import org.apache.fop.fonts.*;
  11. import org.apache.fop.render.pdf.*;
  12. import org.apache.fop.image.*;
  13. import org.apache.fop.datatypes.ColorSpace;
  14. import org.apache.fop.render.pdf.CIDFont;
  15. import org.apache.fop.render.pdf.fonts.LazyFont;
  16. import org.apache.fop.fo.FOUserAgent;
  17. import org.apache.batik.ext.awt.g2d.*;
  18. import org.apache.batik.ext.awt.image.GraphicsUtil;
  19. import java.text.AttributedCharacterIterator;
  20. import java.text.CharacterIterator;
  21. import java.awt.*;
  22. import java.awt.Font;
  23. import java.awt.Image;
  24. import java.awt.image.*;
  25. import java.awt.font.*;
  26. import java.awt.geom.*;
  27. import java.awt.image.renderable.*;
  28. import java.io.*;
  29. import java.util.Map;
  30. import java.util.ArrayList;
  31. import java.util.HashMap;
  32. /**
  33. * PDF Graphics 2D.
  34. * Used for drawing into a pdf document as if it is a graphics object.
  35. * This takes a pdf document and draws into it.
  36. *
  37. * @author <a href="mailto:keiron@aftexsw.com">Keiron Liddle</a>
  38. * @version $Id$
  39. * @see org.apache.batik.ext.awt.g2d.AbstractGraphics2D
  40. */
  41. public class PDFGraphics2D extends AbstractGraphics2D {
  42. boolean standalone = false;
  43. /**
  44. * the PDF Document being created
  45. */
  46. protected PDFDocument pdfDoc;
  47. /**
  48. * the current state of the pdf graphics
  49. */
  50. PDFState graphicsState;
  51. /**
  52. * the current annotation list to add annotations to
  53. */
  54. PDFAnnotList currentAnnotList = null;
  55. protected FontState fontState;
  56. protected FontState ovFontState = null;
  57. /**
  58. * the current stream to add PDF commands to
  59. */
  60. StringWriter currentStream = new StringWriter();
  61. /**
  62. * the current (internal) font name
  63. */
  64. protected String currentFontName;
  65. /**
  66. * the current font size in millipoints
  67. */
  68. protected int currentFontSize;
  69. /**
  70. * the current vertical position in millipoints from bottom
  71. */
  72. protected int currentYPosition = 0;
  73. /**
  74. * the current horizontal position in millipoints from left
  75. */
  76. protected int currentXPosition = 0;
  77. /**
  78. * Create a new PDFGraphics2D with the given pdf document info.
  79. * This is used to create a Graphics object for use inside an already
  80. * existing document.
  81. */
  82. public PDFGraphics2D(boolean textAsShapes, FontState fs, PDFDocument doc,
  83. String font, int size, int xpos, int ypos) {
  84. super(textAsShapes);
  85. pdfDoc = doc;
  86. currentFontName = font;
  87. currentFontSize = size;
  88. currentYPosition = ypos;
  89. currentXPosition = xpos;
  90. fontState = fs;
  91. }
  92. protected PDFGraphics2D(boolean textAsShapes) {
  93. super(textAsShapes);
  94. }
  95. public String getString() {
  96. return currentStream.toString();
  97. }
  98. public void setGraphicContext(GraphicContext c) {
  99. gc = c;
  100. }
  101. public void setOverrideFontState(FontState infont) {
  102. ovFontState = infont;
  103. }
  104. /**
  105. * This constructor supports the create method
  106. */
  107. public PDFGraphics2D(PDFGraphics2D g) {
  108. super(g);
  109. }
  110. /**
  111. * Creates a new <code>Graphics</code> object that is
  112. * a copy of this <code>Graphics</code> object.
  113. * @return a new graphics context that is a copy of
  114. * this graphics context.
  115. */
  116. public Graphics create() {
  117. return new PDFGraphics2D(this);
  118. }
  119. /**
  120. * This is a pdf specific method used to add a link to the
  121. * pdf document.
  122. */
  123. public void addLink(Shape bounds, AffineTransform trans, String dest, int linkType) {
  124. if(currentAnnotList == null) {
  125. currentAnnotList = pdfDoc.makeAnnotList();
  126. }
  127. AffineTransform at = getTransform();
  128. Shape b = at.createTransformedShape(bounds);
  129. b = trans.createTransformedShape(b);
  130. Rectangle rect = b.getBounds();
  131. // this handles the / 1000 in PDFLink
  132. rect.x = rect.x * 1000;
  133. rect.y = rect.y * 1000;
  134. rect.height = -rect.height * 1000;
  135. rect.width = rect.width * 1000;
  136. if(linkType == LinkSet.EXTERNAL) {
  137. String pdfdest = "/XYZ " + dest;
  138. currentAnnotList.addLink(pdfDoc.makeLinkCurrentPage(rect, pdfdest));
  139. } else {
  140. currentAnnotList.addLink(pdfDoc.makeLink(rect,
  141. dest, linkType));
  142. }
  143. }
  144. public PDFAnnotList getAnnotList() {
  145. return currentAnnotList;
  146. }
  147. public void addJpegImage(JpegImage jpeg, float x, float y, float width, float height) {
  148. int xObjectNum = this.pdfDoc.addImage(jpeg);
  149. AffineTransform at = getTransform();
  150. double[] matrix = new double[6];
  151. at.getMatrix(matrix);
  152. currentStream.write("q\n");
  153. Shape imclip = getClip();
  154. writeClip(imclip);
  155. currentStream.write("" + matrix[0] + " " + matrix[1] + " "
  156. + matrix[2] + " " + matrix[3] + " "
  157. + matrix[4] + " " + matrix[5] + " cm\n");
  158. currentStream.write("" + width + " 0 0 "
  159. + (-height) + " "
  160. + x + " "
  161. + (y + height) + " cm\n" + "/Im"
  162. + xObjectNum + " Do\nQ\n");
  163. }
  164. /**
  165. * Draws as much of the specified image as is currently available.
  166. * The image is drawn with its top-left corner at
  167. * (<i>x</i>,&nbsp;<i>y</i>) in this graphics context's coordinate
  168. * space. Transparent pixels in the image do not affect whatever
  169. * pixels are already there.
  170. * <p>
  171. * This method returns immediately in all cases, even if the
  172. * complete image has not yet been loaded, and it has not been dithered
  173. * and converted for the current output device.
  174. * <p>
  175. * If the image has not yet been completely loaded, then
  176. * <code>drawImage</code> returns <code>false</code>. As more of
  177. * the image becomes available, the process that draws the image notifies
  178. * the specified image observer.
  179. * @param img the specified image to be drawn.
  180. * @param x the <i>x</i> coordinate.
  181. * @param y the <i>y</i> coordinate.
  182. * @param observer object to be notified as more of
  183. * the image is converted.
  184. * @see java.awt.Image
  185. * @see java.awt.image.ImageObserver
  186. * @see java.awt.image.ImageObserver#imageUpdate(java.awt.Image, int, int, int, int, int)
  187. */
  188. public boolean drawImage(Image img, int x, int y,
  189. ImageObserver observer) {
  190. // System.err.println("drawImage:x, y");
  191. final int width = img.getWidth(observer);
  192. final int height = img.getHeight(observer);
  193. if (width == -1 || height == -1) {
  194. return false;
  195. }
  196. Dimension size = new Dimension(width * 3, height * 3);
  197. BufferedImage buf = buildBufferedImage(size);
  198. java.awt.Graphics2D g = buf.createGraphics();
  199. g.setComposite(AlphaComposite.SrcOver);
  200. g.setBackground(new Color(1, 1, 1, 0));
  201. g.setPaint(new Color(1, 1, 1, 0));
  202. g.fillRect(0, 0, width * 3, height * 3);
  203. g.clip(new Rectangle(0, 0, buf.getWidth(), buf.getHeight()));
  204. if (!g.drawImage(img, 0, 0, buf.getWidth(), buf.getHeight(), observer)) {
  205. return false;
  206. }
  207. g.dispose();
  208. final byte[] result = new byte[buf.getWidth() * buf.getHeight() * 3];
  209. final byte[] mask = new byte[buf.getWidth() * buf.getHeight()];
  210. Raster raster = buf.getData();
  211. DataBuffer bd = raster.getDataBuffer();
  212. int count = 0;
  213. int maskpos = 0;
  214. int[] iarray;
  215. int i, j, val, alpha, add, mult;
  216. switch (bd.getDataType()) {
  217. case DataBuffer.TYPE_INT:
  218. int[][] idata = ((DataBufferInt)bd).getBankData();
  219. for (i = 0; i < idata.length; i++) {
  220. iarray = idata[i];
  221. for (j = 0; j < iarray.length; j++) {
  222. val = iarray[j];
  223. alpha = val >>> 24;
  224. // mask[maskpos++] = (byte)((idata[i][j] >> 24) & 0xFF);
  225. if (alpha != 255) {
  226. // System.out.println("Alpha: " + alpha);
  227. // Composite with opaque white...
  228. add = (255 - alpha);
  229. mult = (alpha << 16) / 255;
  230. result[count++] =
  231. (byte)(add
  232. + ((((val >> 16) & 0xFF) * mult) >> 16));
  233. result[count++] =
  234. (byte)(add
  235. + ((((val >> 8) & 0xFF) * mult) >> 16));
  236. result[count++] = (byte)(add
  237. + ((((val) & 0xFF) * mult)
  238. >> 16));
  239. } else {
  240. result[count++] = (byte)((val >> 16) & 0xFF);
  241. result[count++] = (byte)((val >> 8) & 0xFF);
  242. result[count++] = (byte)((val) & 0xFF);
  243. }
  244. }
  245. }
  246. break;
  247. default:
  248. // error
  249. break;
  250. }
  251. try {
  252. FopImage fopimg = new TempImage(buf.getWidth(), buf.getHeight(), result, mask);
  253. int xObjectNum = this.pdfDoc.addImage(fopimg);
  254. AffineTransform at = getTransform();
  255. double[] matrix = new double[6];
  256. at.getMatrix(matrix);
  257. currentStream.write("q\n");
  258. Shape imclip = getClip();
  259. writeClip(imclip);
  260. currentStream.write("" + matrix[0] + " " + matrix[1] + " "
  261. + matrix[2] + " " + matrix[3] + " "
  262. + matrix[4] + " " + matrix[5] + " cm\n");
  263. currentStream.write("" + width + " 0 0 " + (-height) + " " + x
  264. + " " + (y + height) + " cm\n" + "/Im"
  265. + xObjectNum + " Do\nQ\n");
  266. } catch (Exception e) {
  267. e.printStackTrace();
  268. }
  269. return true;
  270. }
  271. public BufferedImage buildBufferedImage(Dimension size) {
  272. return new BufferedImage(size.width, size.height,
  273. BufferedImage.TYPE_INT_ARGB);
  274. }
  275. class TempImage implements FopImage {
  276. int m_height;
  277. int m_width;
  278. int m_bitsPerPixel;
  279. ColorSpace m_colorSpace;
  280. int m_bitmapSiye;
  281. byte[] m_bitmaps;
  282. byte[] m_mask;
  283. PDFColor transparent = new PDFColor(255, 255, 255);
  284. TempImage(int width, int height, byte[] result,
  285. byte[] mask) {
  286. this.m_height = height;
  287. this.m_width = width;
  288. this.m_bitsPerPixel = 8;
  289. this.m_colorSpace = new ColorSpace(ColorSpace.DEVICE_RGB);
  290. // this.m_isTransparent = false;
  291. // this.m_bitmapsSize = this.m_width * this.m_height * 3;
  292. this.m_bitmaps = result;
  293. this.m_mask = mask;
  294. }
  295. public boolean load(int type, FOUserAgent ua) {
  296. return true;
  297. }
  298. public String getMimeType() {
  299. return "";
  300. }
  301. public String getURL() {
  302. return "" + m_bitmaps;
  303. }
  304. // image size
  305. public int getWidth() {
  306. return m_width;
  307. }
  308. public int getHeight() {
  309. return m_height;
  310. }
  311. // DeviceGray, DeviceRGB, or DeviceCMYK
  312. public ColorSpace getColorSpace() {
  313. return m_colorSpace;
  314. }
  315. // bits per pixel
  316. public int getBitsPerPixel() {
  317. return m_bitsPerPixel;
  318. }
  319. // For transparent images
  320. public boolean isTransparent() {
  321. return transparent != null;
  322. }
  323. public PDFColor getTransparentColor() {
  324. return transparent;
  325. }
  326. public byte[] getMask() {
  327. return m_mask;
  328. }
  329. // get the image bytes, and bytes properties
  330. // get uncompressed image bytes
  331. public byte[] getBitmaps() {
  332. return m_bitmaps;
  333. }
  334. // width * (bitsPerPixel / 8) * height, no ?
  335. public int getBitmapsSize() {
  336. return m_width * m_height * 3;
  337. }
  338. // get compressed image bytes
  339. // I don't know if we really need it, nor if it
  340. // should be changed...
  341. public byte[] getRessourceBytes() {
  342. return null;
  343. }
  344. public int getRessourceBytesSize() {
  345. return 0;
  346. }
  347. // return null if no corresponding PDFFilter
  348. public PDFFilter getPDFFilter() {
  349. return null;
  350. }
  351. // release memory
  352. public void close() {}
  353. }
  354. /**
  355. * Draws as much of the specified image as has already been scaled
  356. * to fit inside the specified rectangle.
  357. * <p>
  358. * The image is drawn inside the specified rectangle of this
  359. * graphics context's coordinate space, and is scaled if
  360. * necessary. Transparent pixels do not affect whatever pixels
  361. * are already there.
  362. * <p>
  363. * This method returns immediately in all cases, even if the
  364. * entire image has not yet been scaled, dithered, and converted
  365. * for the current output device.
  366. * If the current output representation is not yet complete, then
  367. * <code>drawImage</code> returns <code>false</code>. As more of
  368. * the image becomes available, the process that draws the image notifies
  369. * the image observer by calling its <code>imageUpdate</code> method.
  370. * <p>
  371. * A scaled version of an image will not necessarily be
  372. * available immediately just because an unscaled version of the
  373. * image has been constructed for this output device. Each size of
  374. * the image may be cached separately and generated from the original
  375. * data in a separate image production sequence.
  376. * @param img the specified image to be drawn.
  377. * @param x the <i>x</i> coordinate.
  378. * @param y the <i>y</i> coordinate.
  379. * @param width the width of the rectangle.
  380. * @param height the height of the rectangle.
  381. * @param observer object to be notified as more of
  382. * the image is converted.
  383. * @see java.awt.Image
  384. * @see java.awt.image.ImageObserver
  385. * @see java.awt.image.ImageObserver#imageUpdate(java.awt.Image, int, int, int, int, int)
  386. */
  387. public boolean drawImage(Image img, int x, int y, int width, int height,
  388. ImageObserver observer) {
  389. System.out.println("drawImage");
  390. return true;
  391. }
  392. /**
  393. * Disposes of this graphics context and releases
  394. * any system resources that it is using.
  395. * A <code>Graphics</code> object cannot be used after
  396. * <code>dispose</code>has been called.
  397. * <p>
  398. * When a Java program runs, a large number of <code>Graphics</code>
  399. * objects can be created within a short time frame.
  400. * Although the finalization process of the garbage collector
  401. * also disposes of the same system resources, it is preferable
  402. * to manually free the associated resources by calling this
  403. * method rather than to rely on a finalization process which
  404. * may not run to completion for a long period of time.
  405. * <p>
  406. * Graphics objects which are provided as arguments to the
  407. * <code>paint</code> and <code>update</code> methods
  408. * of components are automatically released by the system when
  409. * those methods return. For efficiency, programmers should
  410. * call <code>dispose</code> when finished using
  411. * a <code>Graphics</code> object only if it was created
  412. * directly from a component or another <code>Graphics</code> object.
  413. * @see java.awt.Graphics#finalize
  414. * @see java.awt.Component#paint
  415. * @see java.awt.Component#update
  416. * @see java.awt.Component#getGraphics
  417. * @see java.awt.Graphics#create
  418. */
  419. public void dispose() {
  420. // System.out.println("dispose");
  421. pdfDoc = null;
  422. fontState = null;
  423. currentStream = null;
  424. currentFontName = null;
  425. }
  426. /**
  427. * Strokes the outline of a <code>Shape</code> using the settings of the
  428. * current <code>Graphics2D</code> context. The rendering attributes
  429. * applied include the <code>Clip</code>, <code>Transform</code>,
  430. * <code>Paint</code>, <code>Composite</code> and
  431. * <code>Stroke</code> attributes.
  432. * @param s the <code>Shape</code> to be rendered
  433. * @see #setStroke
  434. * @see #setPaint
  435. * @see java.awt.Graphics#setColor
  436. * @see #transform
  437. * @see #setTransform
  438. * @see #clip
  439. * @see #setClip
  440. * @see #setComposite
  441. */
  442. public void draw(Shape s) {
  443. // System.out.println("draw(Shape)");
  444. Color c;
  445. c = getColor();
  446. if(c.getAlpha() == 0) {
  447. return;
  448. }
  449. AffineTransform trans = getTransform();
  450. double[] tranvals = new double[6];
  451. trans.getMatrix(tranvals);
  452. Shape imclip = getClip();
  453. boolean newClip = graphicsState.checkClip(imclip);
  454. boolean newTransform = graphicsState.checkTransform(tranvals);
  455. if(newClip || newTransform) {
  456. currentStream.write("q\n");
  457. graphicsState.push();
  458. if(newClip) {
  459. writeClip(imclip);
  460. }
  461. if(newTransform) {
  462. currentStream.write(PDFNumber.doubleOut(tranvals[0], 5) + " "
  463. + PDFNumber.doubleOut(tranvals[1], 5) + " "
  464. + PDFNumber.doubleOut(tranvals[2], 5) + " "
  465. + PDFNumber.doubleOut(tranvals[3], 5) + " "
  466. + PDFNumber.doubleOut(tranvals[4], 5) + " "
  467. + PDFNumber.doubleOut(tranvals[5], 5) + " cm\n");
  468. }
  469. }
  470. applyColor(c, false);
  471. applyPaint(getPaint(), false);
  472. applyStroke(getStroke());
  473. PathIterator iter = s.getPathIterator(new AffineTransform());
  474. while (!iter.isDone()) {
  475. double vals[] = new double[6];
  476. int type = iter.currentSegment(vals);
  477. switch (type) {
  478. case PathIterator.SEG_CUBICTO:
  479. currentStream.write(PDFNumber.doubleOut(vals[0], 5) + " "
  480. + PDFNumber.doubleOut(vals[1], 5) + " "
  481. + PDFNumber.doubleOut(vals[2], 5) + " "
  482. + PDFNumber.doubleOut(vals[3], 5) + " "
  483. + PDFNumber.doubleOut(vals[4], 5) + " "
  484. + PDFNumber.doubleOut(vals[5], 5) + " c\n");
  485. break;
  486. case PathIterator.SEG_LINETO:
  487. currentStream.write(PDFNumber.doubleOut(vals[0], 5) + " "
  488. + PDFNumber.doubleOut(vals[1], 5) + " l\n");
  489. break;
  490. case PathIterator.SEG_MOVETO:
  491. currentStream.write(PDFNumber.doubleOut(vals[0], 5) + " "
  492. + PDFNumber.doubleOut(vals[1], 5) + " m\n");
  493. break;
  494. case PathIterator.SEG_QUADTO:
  495. currentStream.write(PDFNumber.doubleOut(vals[0], 5) + " "
  496. + PDFNumber.doubleOut(vals[1], 5) + " "
  497. + PDFNumber.doubleOut(vals[2], 5) + " "
  498. + PDFNumber.doubleOut(vals[3], 5) + " y\n");
  499. break;
  500. case PathIterator.SEG_CLOSE:
  501. currentStream.write("h\n");
  502. break;
  503. default:
  504. break;
  505. }
  506. iter.next();
  507. }
  508. doDrawing(false, true, false);
  509. if(newClip || newTransform) {
  510. currentStream.write("Q\n");
  511. graphicsState.pop();
  512. }
  513. }
  514. protected void writeClip(Shape s) {
  515. if (s == null) {
  516. return;
  517. }
  518. PathIterator iter = s.getPathIterator(getTransform());
  519. while (!iter.isDone()) {
  520. double vals[] = new double[6];
  521. int type = iter.currentSegment(vals);
  522. switch (type) {
  523. case PathIterator.SEG_CUBICTO:
  524. currentStream.write(PDFNumber.doubleOut(vals[0]) + " "
  525. + PDFNumber.doubleOut(vals[1]) + " "
  526. + PDFNumber.doubleOut(vals[2]) + " "
  527. + PDFNumber.doubleOut(vals[3]) + " "
  528. + PDFNumber.doubleOut(vals[4]) + " "
  529. + PDFNumber.doubleOut(vals[5]) + " c\n");
  530. break;
  531. case PathIterator.SEG_LINETO:
  532. currentStream.write(PDFNumber.doubleOut(vals[0]) + " "
  533. + PDFNumber.doubleOut(vals[1]) + " l\n");
  534. break;
  535. case PathIterator.SEG_MOVETO:
  536. currentStream.write(PDFNumber.doubleOut(vals[0]) + " "
  537. + PDFNumber.doubleOut(vals[1]) + " m\n");
  538. break;
  539. case PathIterator.SEG_QUADTO:
  540. currentStream.write(PDFNumber.doubleOut(vals[0]) + " "
  541. + PDFNumber.doubleOut(vals[1]) + " "
  542. + PDFNumber.doubleOut(vals[2]) + " "
  543. + PDFNumber.doubleOut(vals[3]) + " y\n");
  544. break;
  545. case PathIterator.SEG_CLOSE:
  546. currentStream.write("h\n");
  547. break;
  548. default:
  549. break;
  550. }
  551. iter.next();
  552. }
  553. // clip area
  554. currentStream.write("W\n");
  555. currentStream.write("n\n");
  556. }
  557. protected void applyColor(Color col, boolean fill) {
  558. Color c = col;
  559. if (c.getColorSpace().getType()
  560. == java.awt.color.ColorSpace.TYPE_RGB) {
  561. PDFColor currentColour = new PDFColor(c.getRed(), c.getGreen(),
  562. c.getBlue());
  563. currentStream.write(currentColour.getColorSpaceOut(fill));
  564. } else if (c.getColorSpace().getType()
  565. == java.awt.color.ColorSpace.TYPE_CMYK) {
  566. float[] cComps = c.getColorComponents(new float[3]);
  567. double[] cmyk = new double[3];
  568. for (int i = 0; i < 3; i++) {
  569. // convert the float elements to doubles for pdf
  570. cmyk[i] = cComps[i];
  571. }
  572. PDFColor currentColour = new PDFColor(cmyk[0], cmyk[1], cmyk[2], cmyk[3]);
  573. currentStream.write(currentColour.getColorSpaceOut(fill));
  574. } else if (c.getColorSpace().getType()
  575. == java.awt.color.ColorSpace.TYPE_2CLR) {
  576. // used for black/magenta
  577. float[] cComps = c.getColorComponents(new float[1]);
  578. double[] blackMagenta = new double[1];
  579. for (int i = 0; i < 1; i++) {
  580. blackMagenta[i] = cComps[i];
  581. }
  582. //PDFColor currentColour = new PDFColor(blackMagenta[0], blackMagenta[1]);
  583. //currentStream.write(currentColour.getColorSpaceOut(fill));
  584. } else {
  585. System.err.println("Color Space not supported by PDFGraphics2D");
  586. }
  587. }
  588. protected void applyPaint(Paint paint, boolean fill) {
  589. if (paint instanceof GradientPaint) {
  590. GradientPaint gp = (GradientPaint)paint;
  591. Color c1 = gp.getColor1();
  592. Color c2 = gp.getColor2();
  593. Point2D p1 = gp.getPoint1();
  594. Point2D p2 = gp.getPoint2();
  595. boolean cyclic = gp.isCyclic();
  596. ArrayList theCoords = new ArrayList();
  597. theCoords.add(new Double(p1.getX()));
  598. theCoords.add(new Double(p1.getY()));
  599. theCoords.add(new Double(p2.getX()));
  600. theCoords.add(new Double(p2.getY()));
  601. ArrayList theExtend = new ArrayList();
  602. theExtend.add(new Boolean(true));
  603. theExtend.add(new Boolean(true));
  604. ArrayList theDomain = new ArrayList();
  605. theDomain.add(new Double(0));
  606. theDomain.add(new Double(1));
  607. ArrayList theEncode = new ArrayList();
  608. theEncode.add(new Double(0));
  609. theEncode.add(new Double(1));
  610. theEncode.add(new Double(0));
  611. theEncode.add(new Double(1));
  612. ArrayList theBounds = new ArrayList();
  613. theBounds.add(new Double(0));
  614. theBounds.add(new Double(1));
  615. ArrayList theFunctions = new ArrayList();
  616. ArrayList someColors = new ArrayList();
  617. PDFColor color1 = new PDFColor(c1.getRed(), c1.getGreen(),
  618. c1.getBlue());
  619. someColors.add(color1);
  620. PDFColor color2 = new PDFColor(c2.getRed(), c2.getGreen(),
  621. c2.getBlue());
  622. someColors.add(color2);
  623. PDFFunction myfunc = this.pdfDoc.makeFunction(2, theDomain, null,
  624. color1.getVector(), color2.getVector(), 1.0);
  625. ColorSpace aColorSpace = new ColorSpace(ColorSpace.DEVICE_RGB);
  626. PDFPattern myPat = this.pdfDoc.createGradient(false, aColorSpace,
  627. someColors, null, theCoords);
  628. currentStream.write(myPat.getColorSpaceOut(fill));
  629. } else if (paint instanceof TexturePaint) {}
  630. }
  631. protected void applyStroke(Stroke stroke) {
  632. if (stroke instanceof BasicStroke) {
  633. BasicStroke bs = (BasicStroke)stroke;
  634. float[] da = bs.getDashArray();
  635. if (da != null) {
  636. currentStream.write("[");
  637. for (int count = 0; count < da.length; count++) {
  638. if(((int)da[count]) == 0) {
  639. // the dasharray units in pdf are (whole) numbers
  640. // in user space units, cannot be 0
  641. currentStream.write("1");
  642. } else {
  643. currentStream.write("" + ((int)da[count]));
  644. }
  645. if (count < da.length - 1) {
  646. currentStream.write(" ");
  647. }
  648. }
  649. currentStream.write("] ");
  650. float offset = bs.getDashPhase();
  651. currentStream.write(((int)offset) + " d\n");
  652. }
  653. int ec = bs.getEndCap();
  654. switch (ec) {
  655. case BasicStroke.CAP_BUTT:
  656. currentStream.write(0 + " J\n");
  657. break;
  658. case BasicStroke.CAP_ROUND:
  659. currentStream.write(1 + " J\n");
  660. break;
  661. case BasicStroke.CAP_SQUARE:
  662. currentStream.write(2 + " J\n");
  663. break;
  664. }
  665. int lj = bs.getLineJoin();
  666. switch (lj) {
  667. case BasicStroke.JOIN_MITER:
  668. currentStream.write(0 + " j\n");
  669. break;
  670. case BasicStroke.JOIN_ROUND:
  671. currentStream.write(1 + " j\n");
  672. break;
  673. case BasicStroke.JOIN_BEVEL:
  674. currentStream.write(2 + " j\n");
  675. break;
  676. }
  677. float lw = bs.getLineWidth();
  678. currentStream.write(PDFNumber.doubleOut(lw) + " w\n");
  679. float ml = bs.getMiterLimit();
  680. currentStream.write(PDFNumber.doubleOut(ml) + " M\n");
  681. }
  682. }
  683. /**
  684. * Renders a {@link RenderedImage},
  685. * applying a transform from image
  686. * space into user space before drawing.
  687. * The transformation from user space into device space is done with
  688. * the current <code>Transform</code> in the <code>Graphics2D</code>.
  689. * The specified transformation is applied to the image before the
  690. * transform attribute in the <code>Graphics2D</code> context is applied.
  691. * The rendering attributes applied include the <code>Clip</code>,
  692. * <code>Transform</code>, and <code>Composite</code> attributes. Note
  693. * that no rendering is done if the specified transform is
  694. * noninvertible.
  695. * @param img the image to be rendered
  696. * @param xform the transformation from image space into user space
  697. * @see #transform
  698. * @see #setTransform
  699. * @see #setComposite
  700. * @see #clip
  701. * @see #setClip
  702. */
  703. public void drawRenderedImage(RenderedImage img, AffineTransform xform) {
  704. System.out.println("drawRenderedImage");
  705. }
  706. /**
  707. * Renders a
  708. * {@link RenderableImage},
  709. * applying a transform from image space into user space before drawing.
  710. * The transformation from user space into device space is done with
  711. * the current <code>Transform</code> in the <code>Graphics2D</code>.
  712. * The specified transformation is applied to the image before the
  713. * transform attribute in the <code>Graphics2D</code> context is applied.
  714. * The rendering attributes applied include the <code>Clip</code>,
  715. * <code>Transform</code>, and <code>Composite</code> attributes. Note
  716. * that no rendering is done if the specified transform is
  717. * noninvertible.
  718. * <p>
  719. * Rendering hints set on the <code>Graphics2D</code> object might
  720. * be used in rendering the <code>RenderableImage</code>.
  721. * If explicit control is required over specific hints recognized by a
  722. * specific <code>RenderableImage</code>, or if knowledge of which hints
  723. * are used is required, then a <code>RenderedImage</code> should be
  724. * obtained directly from the <code>RenderableImage</code>
  725. * and rendered using
  726. * {@link #drawRenderedImage(RenderedImage, AffineTransform) drawRenderedImage}.
  727. * @param img the image to be rendered
  728. * @param xform the transformation from image space into user space
  729. * @see #transform
  730. * @see #setTransform
  731. * @see #setComposite
  732. * @see #clip
  733. * @see #setClip
  734. * @see #drawRenderedImage
  735. */
  736. public void drawRenderableImage(RenderableImage img,
  737. AffineTransform xform) {
  738. System.out.println("drawRenderableImage");
  739. }
  740. /**
  741. * Renders the text specified by the specified <code>String</code>,
  742. * using the current <code>Font</code> and <code>Paint</code> attributes
  743. * in the <code>Graphics2D</code> context.
  744. * The baseline of the first character is at position
  745. * (<i>x</i>,&nbsp;<i>y</i>) in the User Space.
  746. * The rendering attributes applied include the <code>Clip</code>,
  747. * <code>Transform</code>, <code>Paint</code>, <code>Font</code> and
  748. * <code>Composite</code> attributes. For characters in script systems
  749. * such as Hebrew and Arabic, the glyphs can be rendered from right to
  750. * left, in which case the coordinate supplied is the location of the
  751. * leftmost character on the baseline.
  752. * @param s the <code>String</code> to be rendered
  753. * @param x,&nbsp;y the coordinates where the <code>String</code>
  754. * should be rendered
  755. * @see #setPaint
  756. * @see java.awt.Graphics#setColor
  757. * @see java.awt.Graphics#setFont
  758. * @see #setTransform
  759. * @see #setComposite
  760. * @see #setClip
  761. */
  762. public void drawString(String s, float x, float y) {
  763. // System.out.println("drawString(String)");
  764. if(ovFontState == null) {
  765. Font gFont = getFont();
  766. String n = gFont.getFamily();
  767. if (n.equals("sanserif")) {
  768. n = "sans-serif";
  769. }
  770. int siz = gFont.getSize();
  771. String style = gFont.isItalic() ? "italic" : "normal";
  772. String weight = gFont.isBold() ? "bold" : "normal";
  773. try {
  774. fontState = new FontState(fontState.getFontInfo(), n, style,
  775. weight, siz * 1000, 0);
  776. } catch (org.apache.fop.apps.FOPException fope) {
  777. fope.printStackTrace();
  778. }
  779. } else {
  780. fontState = ovFontState;
  781. ovFontState = null;
  782. }
  783. String name;
  784. int size;
  785. name = fontState.getFontName();
  786. size = fontState.getFontSize() / 1000;
  787. if ((!name.equals(this.currentFontName))
  788. || (size != this.currentFontSize)) {
  789. this.currentFontName = name;
  790. this.currentFontSize = size;
  791. currentStream.write("/" + name + " " + size + " Tf\n");
  792. }
  793. currentStream.write("q\n");
  794. Shape imclip = getClip();
  795. writeClip(imclip);
  796. Color c = getColor();
  797. applyColor(c, true);
  798. c = getBackground();
  799. applyColor(c, false);
  800. currentStream.write("BT\n");
  801. HashMap kerning = null;
  802. boolean kerningAvailable = false;
  803. kerning = fontState.getKerning();
  804. if (kerning != null &&!kerning.isEmpty()) {
  805. kerningAvailable = true;
  806. }
  807. // This assumes that *all* CIDFonts use a /ToUnicode mapping
  808. boolean useMultiByte = false;
  809. org.apache.fop.render.pdf.Font f =
  810. (org.apache.fop.render.pdf.Font)fontState.getFontInfo().getFonts().get(name);
  811. if (f instanceof LazyFont){
  812. if(((LazyFont) f).getRealFont() instanceof CIDFont){
  813. useMultiByte = true;
  814. }
  815. } else if (f instanceof CIDFont){
  816. useMultiByte = true;
  817. }
  818. // String startText = useMultiByte ? "<FEFF" : "(";
  819. String startText = useMultiByte ? "<" : "(";
  820. String endText = useMultiByte ? "> " : ") ";
  821. AffineTransform trans = getTransform();
  822. trans.translate(x, y);
  823. double[] vals = new double[6];
  824. trans.getMatrix(vals);
  825. currentStream.write(PDFNumber.doubleOut(vals[0]) + " "
  826. + PDFNumber.doubleOut(vals[1]) + " "
  827. + PDFNumber.doubleOut(vals[2]) + " "
  828. + PDFNumber.doubleOut(vals[3]) + " "
  829. + PDFNumber.doubleOut(vals[4]) + " "
  830. + PDFNumber.doubleOut(vals[5]) + " cm\n");
  831. currentStream.write("1 0 0 -1 0 0 Tm [" + startText);
  832. int l = s.length();
  833. for (int i = 0; i < l; i++) {
  834. char ch = fontState.mapChar(s.charAt(i));
  835. if (!useMultiByte) {
  836. if (ch > 127) {
  837. currentStream.write("\\");
  838. currentStream.write(Integer.toOctalString((int)ch));
  839. } else {
  840. switch (ch) {
  841. case '(':
  842. case ')':
  843. case '\\':
  844. currentStream.write("\\");
  845. break;
  846. }
  847. currentStream.write(ch);
  848. }
  849. } else {
  850. currentStream.write(getUnicodeString(ch));
  851. }
  852. if (kerningAvailable && (i + 1) < l) {
  853. addKerning(currentStream, (new Integer((int)ch)),
  854. (new Integer((int)fontState.mapChar(s.charAt(i + 1)))),
  855. kerning, startText, endText);
  856. }
  857. }
  858. currentStream.write(endText);
  859. currentStream.write("] TJ\n");
  860. currentStream.write("ET\n");
  861. currentStream.write("Q\n");
  862. }
  863. private void addKerning(StringWriter buf, Integer ch1, Integer ch2,
  864. HashMap kerning, String startText,
  865. String endText) {
  866. HashMap kernPair = (HashMap)kerning.get(ch1);
  867. if (kernPair != null) {
  868. Integer width = (Integer)kernPair.get(ch2);
  869. if (width != null) {
  870. currentStream.write(endText + (-width.intValue()) + " " + startText);
  871. }
  872. }
  873. }
  874. /**
  875. * Convert a char to a multibyte hex representation
  876. */
  877. private String getUnicodeString(char c) {
  878. StringBuffer buf = new StringBuffer(4);
  879. byte[] uniBytes = null;
  880. try {
  881. char[] a = {
  882. c
  883. };
  884. uniBytes = new String(a).getBytes("UnicodeBigUnmarked");
  885. } catch (Exception e) {
  886. // This should never fail
  887. }
  888. for (int i = 0; i < uniBytes.length; i++) {
  889. int b = (uniBytes[i] < 0) ? (int)(256 + uniBytes[i])
  890. : (int)uniBytes[i];
  891. String hexString = Integer.toHexString(b);
  892. if (hexString.length() == 1)
  893. buf = buf.append("0" + hexString);
  894. else
  895. buf = buf.append(hexString);
  896. }
  897. return buf.toString();
  898. }
  899. /**
  900. * Renders the text of the specified iterator, using the
  901. * <code>Graphics2D</code> context's current <code>Paint</code>. The
  902. * iterator must specify a font
  903. * for each character. The baseline of the
  904. * first character is at position (<i>x</i>,&nbsp;<i>y</i>) in the
  905. * User Space.
  906. * The rendering attributes applied include the <code>Clip</code>,
  907. * <code>Transform</code>, <code>Paint</code>, and
  908. * <code>Composite</code> attributes.
  909. * For characters in script systems such as Hebrew and Arabic,
  910. * the glyphs can be rendered from right to left, in which case the
  911. * coordinate supplied is the location of the leftmost character
  912. * on the baseline.
  913. * @param iterator the iterator whose text is to be rendered
  914. * @param x,&nbsp;y the coordinates where the iterator's text is to be
  915. * rendered
  916. * @see #setPaint
  917. * @see java.awt.Graphics#setColor
  918. * @see #setTransform
  919. * @see #setComposite
  920. * @see #setClip
  921. */
  922. public void drawString(AttributedCharacterIterator iterator, float x,
  923. float y) {
  924. System.err.println("drawString(AttributedCharacterIterator)");
  925. Shape imclip = getClip();
  926. writeClip(imclip);
  927. Color c = getColor();
  928. applyColor(c, true);
  929. c = getBackground();
  930. applyColor(c, false);
  931. currentStream.write("BT\n");
  932. AffineTransform trans = getTransform();
  933. trans.translate(x, y);
  934. double[] vals = new double[6];
  935. trans.getMatrix(vals);
  936. for (char ch = iterator.first(); ch != CharacterIterator.DONE;
  937. ch = iterator.next()) {
  938. Map attr = iterator.getAttributes();
  939. String name = fontState.getFontName();
  940. int size = fontState.getFontSize();
  941. if ((!name.equals(this.currentFontName))
  942. || (size != this.currentFontSize)) {
  943. this.currentFontName = name;
  944. this.currentFontSize = size;
  945. currentStream.write("/" + name + " " + (size / 1000)
  946. + " Tf\n");
  947. }
  948. currentStream.write(PDFNumber.doubleOut(vals[0]) + " "
  949. + PDFNumber.doubleOut(vals[1]) + " "
  950. + PDFNumber.doubleOut(vals[2]) + " "
  951. + PDFNumber.doubleOut(vals[3]) + " "
  952. + PDFNumber.doubleOut(vals[4]) + " "
  953. + PDFNumber.doubleOut(vals[5]) + " Tm (" + ch
  954. + ") Tj\n");
  955. }
  956. currentStream.write("ET\n");
  957. }
  958. /**
  959. * Fills the interior of a <code>Shape</code> using the settings of the
  960. * <code>Graphics2D</code> context. The rendering attributes applied
  961. * include the <code>Clip</code>, <code>Transform</code>,
  962. * <code>Paint</code>, and <code>Composite</code>.
  963. * @param s the <code>Shape</code> to be filled
  964. * @see #setPaint
  965. * @see java.awt.Graphics#setColor
  966. * @see #transform
  967. * @see #setTransform
  968. * @see #setComposite
  969. * @see #clip
  970. * @see #setClip
  971. */
  972. public void fill(Shape s) {
  973. // System.err.println("fill");
  974. Color c;
  975. c = getBackground();
  976. if(c.getAlpha() == 0) {
  977. c = getColor();
  978. if(c.getAlpha() == 0) {
  979. return;
  980. }
  981. }
  982. Shape imclip = getClip();
  983. boolean newState = graphicsState.checkClip(imclip);
  984. if(newState) {
  985. currentStream.write("q\n");
  986. graphicsState.push();
  987. writeClip(imclip);
  988. graphicsState.setClip(imclip);
  989. }
  990. c = getColor();
  991. if(graphicsState.setColor(c)) {
  992. applyColor(c, true);
  993. }
  994. c = getBackground();
  995. if(graphicsState.setBackColor(c)) {
  996. applyColor(c, false);
  997. }
  998. Paint paint = getPaint();
  999. if(graphicsState.setPaint(paint)) {
  1000. applyPaint(paint, true);
  1001. }
  1002. PathIterator iter = s.getPathIterator(getTransform());
  1003. while (!iter.isDone()) {
  1004. double vals[] = new double[6];
  1005. int type = iter.currentSegment(vals);
  1006. switch (type) {
  1007. case PathIterator.SEG_CUBICTO:
  1008. currentStream.write(PDFNumber.doubleOut(vals[0], 5) + " "
  1009. + PDFNumber.doubleOut(vals[1], 5) + " "
  1010. + PDFNumber.doubleOut(vals[2], 5) + " "
  1011. + PDFNumber.doubleOut(vals[3], 5) + " "
  1012. + PDFNumber.doubleOut(vals[4], 5) + " "
  1013. + PDFNumber.doubleOut(vals[5], 5) + " c\n");
  1014. break;
  1015. case PathIterator.SEG_LINETO:
  1016. currentStream.write(PDFNumber.doubleOut(vals[0], 5) + " "
  1017. + PDFNumber.doubleOut(vals[1], 5) + " l\n");
  1018. break;
  1019. case PathIterator.SEG_MOVETO:
  1020. currentStream.write(PDFNumber.doubleOut(vals[0], 5) + " "
  1021. + PDFNumber.doubleOut(vals[1], 5) + " m\n");
  1022. break;
  1023. case PathIterator.SEG_QUADTO:
  1024. currentStream.write(PDFNumber.doubleOut(vals[0], 5) + " "
  1025. + PDFNumber.doubleOut(vals[1], 5) + " "
  1026. + PDFNumber.doubleOut(vals[2], 5) + " "
  1027. + PDFNumber.doubleOut(vals[3], 5) + " y\n");
  1028. break;
  1029. case PathIterator.SEG_CLOSE:
  1030. currentStream.write("h\n");
  1031. break;
  1032. default:
  1033. break;
  1034. }
  1035. iter.next();
  1036. }
  1037. doDrawing(true, false,
  1038. iter.getWindingRule() == PathIterator.WIND_EVEN_ODD);
  1039. if(newState) {
  1040. currentStream.write("Q\n");
  1041. graphicsState.pop();
  1042. }
  1043. }
  1044. protected void doDrawing(boolean fill, boolean stroke, boolean nonzero) {
  1045. if (fill) {
  1046. if (stroke) {
  1047. if (nonzero)
  1048. currentStream.write("B*\n");
  1049. else
  1050. currentStream.write("B\n");
  1051. } else {
  1052. if (nonzero)
  1053. currentStream.write("f*\n");
  1054. else
  1055. currentStream.write("f\n");
  1056. }
  1057. } else {
  1058. // if(stroke)
  1059. currentStream.write("S\n");
  1060. }
  1061. }
  1062. /**
  1063. * Returns the device configuration associated with this
  1064. * <code>Graphics2D</code>.
  1065. */
  1066. public GraphicsConfiguration getDeviceConfiguration() {
  1067. return new PDFGraphicsConfiguration();
  1068. }
  1069. /**
  1070. * Our implementation of the class that returns information about
  1071. * roughly what we can handle and want to see (alpha for example).
  1072. */
  1073. static class PDFGraphicsConfiguration extends GraphicsConfiguration {
  1074. // We use this to get a good colormodel..
  1075. static BufferedImage BIWithAlpha = new BufferedImage(1, 1,
  1076. BufferedImage.TYPE_INT_ARGB);
  1077. // We use this to get a good colormodel..
  1078. static BufferedImage BIWithOutAlpha = new BufferedImage(1, 1,
  1079. BufferedImage.TYPE_INT_RGB);
  1080. /**
  1081. * Construct a buffered image with an alpha channel, unless
  1082. * transparencty is OPAQUE (no alpha at all).
  1083. */
  1084. public BufferedImage createCompatibleImage(int width, int height,
  1085. int transparency) {
  1086. if (transparency == Transparency.OPAQUE)
  1087. return new BufferedImage(width, height,
  1088. BufferedImage.TYPE_INT_RGB);
  1089. else
  1090. return new BufferedImage(width, height,
  1091. BufferedImage.TYPE_INT_ARGB);
  1092. }
  1093. /**
  1094. * Construct a buffered image with an alpha channel.
  1095. */
  1096. public BufferedImage createCompatibleImage(int width, int height) {
  1097. return new BufferedImage(width, height,
  1098. BufferedImage.TYPE_INT_ARGB);
  1099. }
  1100. /**
  1101. * FIXX ME: This should return the page bounds in Pts,
  1102. * I couldn't figure out how to get this for the current
  1103. * page from the PDFDocument (this still works for now,
  1104. * but it should be fixed...).
  1105. */
  1106. public Rectangle getBounds() {
  1107. System.out.println("getting getBounds");
  1108. return null;
  1109. }
  1110. /**
  1111. * Return a good default color model for this 'device'.
  1112. */
  1113. public ColorModel getColorModel() {
  1114. return BIWithAlpha.getColorModel();
  1115. }
  1116. /**
  1117. * Return a good color model given <tt>transparency</tt>
  1118. */
  1119. public ColorModel getColorModel(int transparency) {
  1120. if (transparency == Transparency.OPAQUE)
  1121. return BIWithOutAlpha.getColorModel();
  1122. else
  1123. return BIWithAlpha.getColorModel();
  1124. }
  1125. /**
  1126. * The default transform (1:1).
  1127. */
  1128. public AffineTransform getDefaultTransform() {
  1129. System.out.println("getting getDefaultTransform");
  1130. return new AffineTransform();
  1131. }
  1132. /**
  1133. * The normalizing transform (1:1) (since we currently
  1134. * render images at 72dpi, which we might want to change
  1135. * in the future).
  1136. */
  1137. public AffineTransform getNormalizingTransform() {
  1138. System.out.println("getting getNormalizingTransform");
  1139. return new AffineTransform(2, 0, 0, 2, 0, 0);
  1140. }
  1141. /**
  1142. * Return our dummy instance of GraphicsDevice
  1143. */
  1144. public GraphicsDevice getDevice() {
  1145. return new PDFGraphicsDevice(this);
  1146. }
  1147. /*
  1148. // for jdk1.4
  1149. public java.awt.image.VolatileImage createCompatibleVolatileImage(int width, int height) {
  1150. return null;
  1151. }
  1152. */
  1153. }
  1154. /**
  1155. * This implements the GraphicsDevice interface as appropriate for
  1156. * a PDFGraphics2D. This is quite simple since we only have one
  1157. * GraphicsConfiguration for now (this might change in the future
  1158. * I suppose).
  1159. */
  1160. static class PDFGraphicsDevice extends GraphicsDevice {
  1161. /**
  1162. * The Graphics Config that created us...
  1163. */
  1164. GraphicsConfiguration gc;
  1165. /**
  1166. * @param The gc we should reference
  1167. */
  1168. PDFGraphicsDevice(PDFGraphicsConfiguration gc) {
  1169. this.gc = gc;
  1170. }
  1171. /**
  1172. * Ignore template and return the only config we have
  1173. */
  1174. public GraphicsConfiguration getBestConfiguration(GraphicsConfigTemplate gct) {
  1175. return gc;
  1176. }
  1177. /**
  1178. * Return an array of our one GraphicsConfig
  1179. */
  1180. public GraphicsConfiguration[] getConfigurations() {
  1181. return new GraphicsConfiguration[] {
  1182. gc
  1183. };
  1184. }
  1185. /**
  1186. * Return out sole GraphicsConfig.
  1187. */
  1188. public GraphicsConfiguration getDefaultConfiguration() {
  1189. return gc;
  1190. }
  1191. /**
  1192. * Generate an IdString..
  1193. */
  1194. public String getIDstring() {
  1195. return toString();
  1196. }
  1197. /**
  1198. * Let the caller know that we are "a printer"
  1199. */
  1200. public int getType() {
  1201. return GraphicsDevice.TYPE_PRINTER;
  1202. }
  1203. }
  1204. /**
  1205. * Used to create proper font metrics
  1206. */
  1207. private Graphics2D fmg;
  1208. {
  1209. BufferedImage bi = new BufferedImage(1, 1,
  1210. BufferedImage.TYPE_INT_ARGB);
  1211. fmg = bi.createGraphics();
  1212. }
  1213. /**
  1214. * Gets the font metrics for the specified font.
  1215. * @return the font metrics for the specified font.
  1216. * @param f the specified font
  1217. * @see java.awt.Graphics#getFont
  1218. * @see java.awt.FontMetrics
  1219. * @see java.awt.Graphics#getFontMetrics()
  1220. */
  1221. public FontMetrics getFontMetrics(Font f) {
  1222. return fmg.getFontMetrics(f);
  1223. }
  1224. /**
  1225. * Sets the paint mode of this graphics context to alternate between
  1226. * this graphics context's current color and the new specified color.
  1227. * This specifies that logical pixel operations are performed in the
  1228. * XOR mode, which alternates pixels between the current color and
  1229. * a specified XOR color.
  1230. * <p>
  1231. * When drawing operations are performed, pixels which are the
  1232. * current color are changed to the specified color, and vice versa.
  1233. * <p>
  1234. * Pixels that are of colors other than those two colors are changed
  1235. * in an unpredictable but reversible manner; if the same figure is
  1236. * drawn twice, then all pixels are restored to their original values.
  1237. * @param c1 the XOR alternation color
  1238. */
  1239. public void setXORMode(Color c1) {
  1240. System.out.println("setXORMode");
  1241. }
  1242. /**
  1243. * Copies an area of the component by a distance specified by
  1244. * <code>dx</code> and <code>dy</code>. From the point specified
  1245. * by <code>x</code> and <code>y</code>, this method
  1246. * copies downwards and to the right. To copy an area of the
  1247. * component to the left or upwards, specify a negative value for
  1248. * <code>dx</code> or <code>dy</code>.
  1249. * If a portion of the source rectangle lies outside the bounds
  1250. * of the component, or is obscured by another window or component,
  1251. * <code>copyArea</code> will be unable to copy the associated
  1252. * pixels. The area that is omitted can be refreshed by calling
  1253. * the component's <code>paint</code> method.
  1254. * @param x the <i>x</i> coordinate of the source rectangle.
  1255. * @param y the <i>y</i> coordinate of the source rectangle.
  1256. * @param width the width of the source rectangle.
  1257. * @param height the height of the source rectangle.
  1258. * @param dx the horizontal distance to copy the pixels.
  1259. * @param dy the vertical distance to copy the pixels.
  1260. */
  1261. public void copyArea(int x, int y, int width, int height, int dx,
  1262. int dy) {
  1263. System.out.println("copyArea");
  1264. }
  1265. }