Vous ne pouvez pas sélectionner plus de 25 sujets Les noms de sujets doivent commencer par une lettre ou un nombre, peuvent contenir des tirets ('-') et peuvent comporter jusqu'à 35 caractères.

PSGraphics2D.java 41KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176
  1. /*
  2. * Copyright 1999-2005 The Apache Software Foundation.
  3. *
  4. * Licensed under the Apache License, Version 2.0 (the "License");
  5. * you may not use this file except in compliance with the License.
  6. * You may obtain a copy of the License at
  7. *
  8. * http://www.apache.org/licenses/LICENSE-2.0
  9. *
  10. * Unless required by applicable law or agreed to in writing, software
  11. * distributed under the License is distributed on an "AS IS" BASIS,
  12. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13. * See the License for the specific language governing permissions and
  14. * limitations under the License.
  15. */
  16. /* $Id$ */
  17. package org.apache.fop.render.ps;
  18. //Java
  19. import java.text.AttributedCharacterIterator;
  20. import java.awt.AlphaComposite;
  21. import java.awt.BasicStroke;
  22. import java.awt.Color;
  23. import java.awt.Dimension;
  24. /* java.awt.Font is not imported to avoid confusion with
  25. org.apache.fop.fonts.Font */
  26. import java.awt.GradientPaint;
  27. import java.awt.Graphics;
  28. import java.awt.Graphics2D;
  29. import java.awt.GraphicsConfiguration;
  30. import java.awt.GraphicsEnvironment;
  31. import java.awt.Image;
  32. import java.awt.Paint;
  33. import java.awt.Rectangle;
  34. import java.awt.Shape;
  35. import java.awt.Stroke;
  36. import java.awt.TexturePaint;
  37. import java.awt.color.ColorSpace;
  38. import java.awt.color.ICC_Profile;
  39. import java.awt.font.FontRenderContext;
  40. import java.awt.font.GlyphVector;
  41. import java.awt.geom.AffineTransform;
  42. import java.awt.geom.PathIterator;
  43. import java.awt.image.BufferedImage;
  44. import java.awt.image.DataBuffer;
  45. import java.awt.image.DataBufferInt;
  46. import java.awt.image.ImageObserver;
  47. import java.awt.image.Raster;
  48. import java.awt.image.RenderedImage;
  49. import java.awt.image.renderable.RenderableImage;
  50. import java.io.IOException;
  51. //Batik
  52. import org.apache.batik.ext.awt.RenderingHintsKeyExt;
  53. import org.apache.batik.ext.awt.g2d.AbstractGraphics2D;
  54. import org.apache.batik.ext.awt.g2d.GraphicContext;
  55. import org.apache.commons.logging.Log;
  56. import org.apache.commons.logging.LogFactory;
  57. //FOP
  58. import org.apache.fop.fonts.Font;
  59. import org.apache.fop.fonts.FontInfo;
  60. import org.apache.fop.image.FopImage;
  61. /**
  62. * This concrete implementation of <tt>AbstractGraphics2D</tt> is a
  63. * simple help to programmers to get started with their own
  64. * implementation of <tt>Graphics2D</tt>.
  65. * <tt>DefaultGraphics2D</tt> implements all the abstract methods
  66. * is <tt>AbstractGraphics2D</tt> and makes it easy to start
  67. * implementing a <tt>Graphic2D</tt> piece-meal.
  68. *
  69. * @author <a href="mailto:keiron@aftexsw.com">Keiron Liddle</a>
  70. * @version $Id$
  71. * @see org.apache.batik.ext.awt.g2d.AbstractGraphics2D
  72. */
  73. public class PSGraphics2D extends AbstractGraphics2D {
  74. private static final AffineTransform IDENTITY_TRANSFORM = new AffineTransform();
  75. /** the logger for this class */
  76. protected Log log = LogFactory.getLog(PSTextPainter.class);
  77. /** the PostScript generator being created */
  78. protected PSGenerator gen;
  79. private boolean clippingDisabled = false;
  80. /** Currently valid FontState */
  81. protected Font font;
  82. /** Overriding FontState */
  83. protected Font overrideFont = null;
  84. /** the current (internal) font name */
  85. protected String currentFontName;
  86. /** the current font size in millipoints */
  87. protected int currentFontSize;
  88. /**
  89. * the current colour for use in svg
  90. */
  91. protected Color currentColour = new Color(0, 0, 0);
  92. /** FontInfo containing all available fonts */
  93. protected FontInfo fontInfo;
  94. /**
  95. * Create a new Graphics2D that generates PostScript code.
  96. * @param textAsShapes True if text should be rendered as graphics
  97. * @see org.apache.batik.ext.awt.g2d.AbstractGraphics2D#AbstractGraphics2D(boolean)
  98. */
  99. public PSGraphics2D(boolean textAsShapes) {
  100. super(textAsShapes);
  101. }
  102. /**
  103. * Create a new Graphics2D that generates PostScript code.
  104. * @param textAsShapes True if text should be rendered as graphics
  105. * @param gen PostScript generator to use for output
  106. * @see org.apache.batik.ext.awt.g2d.AbstractGraphics2D#AbstractGraphics2D(boolean)
  107. */
  108. public PSGraphics2D(boolean textAsShapes, PSGenerator gen) {
  109. this(textAsShapes);
  110. setPSGenerator(gen);
  111. }
  112. /**
  113. * Constructor for creating copies
  114. * @param g parent PostScript Graphics2D
  115. */
  116. public PSGraphics2D(PSGraphics2D g) {
  117. super(g);
  118. setPSGenerator(g.gen);
  119. this.clippingDisabled = g.clippingDisabled;
  120. this.font = g.font;
  121. this.overrideFont = g.overrideFont;
  122. this.currentFontName = g.currentFontName;
  123. this.currentFontSize = g.currentFontSize;
  124. this.currentColour = g.currentColour;
  125. this.fontInfo = g.fontInfo;
  126. }
  127. /**
  128. * Sets the PostScript generator
  129. * @param gen the PostScript generator
  130. */
  131. public void setPSGenerator(PSGenerator gen) {
  132. this.gen = gen;
  133. }
  134. /**
  135. * Sets the GraphicContext
  136. * @param c GraphicContext to use
  137. */
  138. public void setGraphicContext(GraphicContext c) {
  139. gc = c;
  140. setPrivateHints();
  141. }
  142. private void setPrivateHints() {
  143. setRenderingHint(RenderingHintsKeyExt.KEY_AVOID_TILE_PAINTING,
  144. RenderingHintsKeyExt.VALUE_AVOID_TILE_PAINTING_ON);
  145. }
  146. /**
  147. * Creates a new <code>Graphics</code> object that is
  148. * a copy of this <code>Graphics</code> object.
  149. * @return a new graphics context that is a copy of
  150. * this graphics context.
  151. */
  152. public Graphics create() {
  153. return new PSGraphics2D(this);
  154. }
  155. /**
  156. * Return the font information associated with this object
  157. * @return the FontInfo object
  158. */
  159. public FontInfo getFontInfo() {
  160. return fontInfo;
  161. }
  162. /**
  163. * Central handler for IOExceptions for this class.
  164. * @param ioe IOException to handle
  165. */
  166. protected void handleIOException(IOException ioe) {
  167. //TODO Surely, there's a better way to do this.
  168. ioe.printStackTrace();
  169. }
  170. /**
  171. * This method is used by AbstractPSDocumentGraphics2D to prepare a new page if
  172. * necessary.
  173. */
  174. protected void preparePainting() {
  175. //nop, used by AbstractPSDocumentGraphics2D
  176. }
  177. /**
  178. * Draws as much of the specified image as is currently available.
  179. * The image is drawn with its top-left corner at
  180. * (<i>x</i>,&nbsp;<i>y</i>) in this graphics context's coordinate
  181. * space. Transparent pixels in the image do not affect whatever
  182. * pixels are already there.
  183. * <p>
  184. * This method returns immediately in all cases, even if the
  185. * complete image has not yet been loaded, and it has not been dithered
  186. * and converted for the current output device.
  187. * <p>
  188. * If the image has not yet been completely loaded, then
  189. * <code>drawImage</code> returns <code>false</code>. As more of
  190. * the image becomes available, the process that draws the image notifies
  191. * the specified image observer.
  192. * @param img the specified image to be drawn.
  193. * @param x the <i>x</i> coordinate.
  194. * @param y the <i>y</i> coordinate.
  195. * @param observer object to be notified as more of
  196. * the image is converted.
  197. * @return True if the image has been fully drawn/loaded
  198. * @see java.awt.Image
  199. * @see java.awt.image.ImageObserver
  200. * @see java.awt.image.ImageObserver#imageUpdate(java.awt.Image, int, int, int, int, int)
  201. */
  202. public boolean drawImage(Image img, int x, int y,
  203. ImageObserver observer) {
  204. preparePainting();
  205. log.debug("drawImage: " + x + ", " + y + " " + img.getClass().getName());
  206. final int width = img.getWidth(observer);
  207. final int height = img.getHeight(observer);
  208. if (width == -1 || height == -1) {
  209. return false;
  210. }
  211. Dimension size = new Dimension(width, height);
  212. BufferedImage buf = buildBufferedImage(size);
  213. java.awt.Graphics2D g = buf.createGraphics();
  214. g.setComposite(AlphaComposite.SrcOver);
  215. g.setBackground(new Color(1, 1, 1, 0));
  216. g.setPaint(new Color(1, 1, 1, 0));
  217. g.fillRect(0, 0, width, height);
  218. g.clip(new Rectangle(0, 0, buf.getWidth(), buf.getHeight()));
  219. if (!g.drawImage(img, 0, 0, observer)) {
  220. return false;
  221. }
  222. g.dispose();
  223. final byte[] result = new byte[buf.getWidth() * buf.getHeight() * 3];
  224. //final byte[] mask = new byte[buf.getWidth() * buf.getHeight()];
  225. Raster raster = buf.getData();
  226. DataBuffer bd = raster.getDataBuffer();
  227. int count = 0;
  228. //int maskpos = 0;
  229. switch (bd.getDataType()) {
  230. case DataBuffer.TYPE_INT:
  231. int[][] idata = ((DataBufferInt)bd).getBankData();
  232. for (int i = 0; i < idata.length; i++) {
  233. for (int j = 0; j < idata[i].length; j++) {
  234. // mask[maskpos++] = (byte)((idata[i][j] >> 24) & 0xFF);
  235. if (((idata[i][j] >> 24) & 0xFF) != 255) {
  236. result[count++] = (byte)0xFF;
  237. result[count++] = (byte)0xFF;
  238. result[count++] = (byte)0xFF;
  239. } else {
  240. result[count++] = (byte)((idata[i][j] >> 16) & 0xFF);
  241. result[count++] = (byte)((idata[i][j] >> 8) & 0xFF);
  242. result[count++] = (byte)((idata[i][j]) & 0xFF);
  243. }
  244. }
  245. }
  246. break;
  247. default:
  248. // error
  249. break;
  250. }
  251. try {
  252. FopImage fopimg = new TempImage(width, height, result, null);
  253. AffineTransform at = getTransform();
  254. gen.saveGraphicsState();
  255. gen.concatMatrix(at);
  256. Shape imclip = getClip();
  257. writeClip(imclip);
  258. PSImageUtils.renderBitmapImage(fopimg,
  259. x, y, width, height, gen);
  260. gen.restoreGraphicsState();
  261. } catch (IOException ioe) {
  262. handleIOException(ioe);
  263. }
  264. return true;
  265. }
  266. /**
  267. * Creates a buffered image.
  268. * @param size dimensions of the image to be created
  269. * @return the buffered image
  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. private int height;
  277. private int width;
  278. private int bitsPerPixel;
  279. private ColorSpace colorSpace;
  280. private byte[] bitmaps;
  281. private byte[] mask;
  282. private Color transparentColor;
  283. TempImage(int width, int height, byte[] bitmaps,
  284. byte[] mask) {
  285. this.height = height;
  286. this.width = width;
  287. this.bitsPerPixel = 8;
  288. this.colorSpace = ColorSpace.getInstance(ColorSpace.CS_sRGB);
  289. this.bitmaps = bitmaps;
  290. this.mask = mask;
  291. }
  292. public String getMimeType() {
  293. return "application/octet-stream";
  294. }
  295. public String getOriginalURI() {
  296. return "temp-image:" + this.toString();
  297. }
  298. /**
  299. * @see org.apache.fop.image.FopImage#load(int, org.apache.commons.logging.Log)
  300. */
  301. public boolean load(int type) {
  302. switch (type) {
  303. case FopImage.DIMENSIONS: break;
  304. case FopImage.BITMAP: break;
  305. case FopImage.ORIGINAL_DATA: break;
  306. default: throw new RuntimeException("Unknown load type: " + type);
  307. }
  308. return true;
  309. }
  310. public int getWidth() {
  311. return this.width;
  312. }
  313. public int getHeight() {
  314. return this.height;
  315. }
  316. public ColorSpace getColorSpace() {
  317. return this.colorSpace;
  318. }
  319. public ICC_Profile getICCProfile() {
  320. return null;
  321. }
  322. public int getBitsPerPixel() {
  323. return this.bitsPerPixel;
  324. }
  325. // For transparent images
  326. public boolean isTransparent() {
  327. return getTransparentColor() != null;
  328. }
  329. public Color getTransparentColor() {
  330. return this.transparentColor;
  331. }
  332. public boolean hasSoftMask() {
  333. return this.mask != null;
  334. }
  335. public byte[] getSoftMask() {
  336. return this.mask;
  337. }
  338. public byte[] getBitmaps() {
  339. return this.bitmaps;
  340. }
  341. // width * (bitsPerPixel / 8) * height, no ?
  342. public int getBitmapsSize() {
  343. return getWidth() * getHeight() * 3; //Assumes RGB!
  344. }
  345. // get compressed image bytes
  346. // I don't know if we really need it, nor if it
  347. // should be changed...
  348. public byte[] getRessourceBytes() {
  349. return null;
  350. }
  351. public int getRessourceBytesSize() {
  352. return 0;
  353. }
  354. /** @see org.apache.fop.image.FopImage#getIntrinsicWidth() */
  355. public int getIntrinsicWidth() {
  356. return (int)(getWidth() * 72 / getHorizontalResolution());
  357. }
  358. /** @see org.apache.fop.image.FopImage#getIntrinsicHeight() */
  359. public int getIntrinsicHeight() {
  360. return (int)(getHeight() * 72 / getVerticalResolution());
  361. }
  362. /** @see org.apache.fop.image.FopImage#getHorizontalResolution() */
  363. public double getHorizontalResolution() {
  364. return 72;
  365. }
  366. /** @see org.apache.fop.image.FopImage#getVerticalResolution() */
  367. public double getVerticalResolution() {
  368. return 72;
  369. }
  370. }
  371. /**
  372. * Draws as much of the specified image as has already been scaled
  373. * to fit inside the specified rectangle.
  374. * <p>
  375. * The image is drawn inside the specified rectangle of this
  376. * graphics context's coordinate space, and is scaled if
  377. * necessary. Transparent pixels do not affect whatever pixels
  378. * are already there.
  379. * <p>
  380. * This method returns immediately in all cases, even if the
  381. * entire image has not yet been scaled, dithered, and converted
  382. * for the current output device.
  383. * If the current output representation is not yet complete, then
  384. * <code>drawImage</code> returns <code>false</code>. As more of
  385. * the image becomes available, the process that draws the image notifies
  386. * the image observer by calling its <code>imageUpdate</code> method.
  387. * <p>
  388. * A scaled version of an image will not necessarily be
  389. * available immediately just because an unscaled version of the
  390. * image has been constructed for this output device. Each size of
  391. * the image may be cached separately and generated from the original
  392. * data in a separate image production sequence.
  393. * @param img the specified image to be drawn.
  394. * @param x the <i>x</i> coordinate.
  395. * @param y the <i>y</i> coordinate.
  396. * @param width the width of the rectangle.
  397. * @param height the height of the rectangle.
  398. * @param observer object to be notified as more of
  399. * the image is converted.
  400. * @return True if the image has been fully loaded/drawn
  401. * @see java.awt.Image
  402. * @see java.awt.image.ImageObserver
  403. * @see java.awt.image.ImageObserver#imageUpdate(java.awt.Image, int, int, int, int, int)
  404. */
  405. public boolean drawImage(Image img, int x, int y, int width, int height,
  406. ImageObserver observer) {
  407. preparePainting();
  408. log.warn("NYI: drawImage");
  409. return true;
  410. }
  411. /**
  412. * Disposes of this graphics context and releases
  413. * any system resources that it is using.
  414. * A <code>Graphics</code> object cannot be used after
  415. * <code>dispose</code>has been called.
  416. * <p>
  417. * When a Java program runs, a large number of <code>Graphics</code>
  418. * objects can be created within a short time frame.
  419. * Although the finalization process of the garbage collector
  420. * also disposes of the same system resources, it is preferable
  421. * to manually free the associated resources by calling this
  422. * method rather than to rely on a finalization process which
  423. * may not run to completion for a long period of time.
  424. * <p>
  425. * Graphics objects which are provided as arguments to the
  426. * <code>paint</code> and <code>update</code> methods
  427. * of components are automatically released by the system when
  428. * those methods return. For efficiency, programmers should
  429. * call <code>dispose</code> when finished using
  430. * a <code>Graphics</code> object only if it was created
  431. * directly from a component or another <code>Graphics</code> object.
  432. * @see java.awt.Graphics#finalize
  433. * @see java.awt.Component#paint
  434. * @see java.awt.Component#update
  435. * @see java.awt.Component#getGraphics
  436. * @see java.awt.Graphics#create
  437. */
  438. public void dispose() {
  439. this.gen = null;
  440. this.font = null;
  441. this.currentColour = null;
  442. this.fontInfo = null;
  443. }
  444. /**
  445. * Processes a path iterator generating the nexessary painting operations.
  446. * @param iter PathIterator to process
  447. * @throws IOException In case of an I/O problem.
  448. */
  449. public void processPathIterator(PathIterator iter) throws IOException {
  450. double[] vals = new double[6];
  451. while (!iter.isDone()) {
  452. int type = iter.currentSegment(vals);
  453. switch (type) {
  454. case PathIterator.SEG_CUBICTO:
  455. gen.writeln(gen.formatDouble(vals[0]) + " "
  456. + gen.formatDouble(vals[1]) + " "
  457. + gen.formatDouble(vals[2]) + " "
  458. + gen.formatDouble(vals[3]) + " "
  459. + gen.formatDouble(vals[4]) + " "
  460. + gen.formatDouble(vals[5])
  461. + " curveto");
  462. break;
  463. case PathIterator.SEG_LINETO:
  464. gen.writeln(gen.formatDouble(vals[0]) + " "
  465. + gen.formatDouble(vals[1])
  466. + " lineto");
  467. break;
  468. case PathIterator.SEG_MOVETO:
  469. gen.writeln(gen.formatDouble(vals[0]) + " "
  470. + gen.formatDouble(vals[1])
  471. + " M");
  472. break;
  473. case PathIterator.SEG_QUADTO:
  474. gen.writeln(gen.formatDouble(vals[0]) + " "
  475. + gen.formatDouble(vals[1]) + " "
  476. + gen.formatDouble(vals[2]) + " "
  477. + gen.formatDouble(vals[3]) + " QUADTO ");
  478. break;
  479. case PathIterator.SEG_CLOSE:
  480. gen.writeln("closepath");
  481. break;
  482. default:
  483. break;
  484. }
  485. iter.next();
  486. }
  487. }
  488. /**
  489. * Strokes the outline of a <code>Shape</code> using the settings of the
  490. * current <code>Graphics2D</code> context. The rendering attributes
  491. * applied include the <code>Clip</code>, <code>Transform</code>,
  492. * <code>Paint</code>, <code>Composite</code> and
  493. * <code>Stroke</code> attributes.
  494. * @param s the <code>Shape</code> to be rendered
  495. * @see #setStroke
  496. * @see #setPaint
  497. * @see java.awt.Graphics#setColor
  498. * @see #transform
  499. * @see #setTransform
  500. * @see #clip
  501. * @see #setClip
  502. * @see #setComposite
  503. */
  504. public void draw(Shape s) {
  505. preparePainting();
  506. try {
  507. gen.saveGraphicsState();
  508. AffineTransform trans = getTransform();
  509. boolean newTransform = gen.getCurrentState().checkTransform(trans)
  510. && !trans.isIdentity();
  511. if (newTransform) {
  512. gen.concatMatrix(trans);
  513. }
  514. Shape imclip = getClip();
  515. writeClip(imclip);
  516. establishColor(getColor());
  517. applyPaint(getPaint(), false);
  518. applyStroke(getStroke());
  519. gen.writeln("newpath");
  520. PathIterator iter = s.getPathIterator(IDENTITY_TRANSFORM);
  521. processPathIterator(iter);
  522. doDrawing(false, true, false);
  523. gen.restoreGraphicsState();
  524. } catch (IOException ioe) {
  525. handleIOException(ioe);
  526. }
  527. }
  528. /**
  529. * Establishes a clipping region
  530. * @param s Shape defining the clipping region
  531. */
  532. protected void writeClip(Shape s) {
  533. if (s == null) {
  534. return;
  535. }
  536. if (!this.clippingDisabled) {
  537. preparePainting();
  538. try {
  539. gen.writeln("newpath");
  540. PathIterator iter = s.getPathIterator(IDENTITY_TRANSFORM);
  541. processPathIterator(iter);
  542. // clip area
  543. gen.writeln("clip");
  544. } catch (IOException ioe) {
  545. handleIOException(ioe);
  546. }
  547. }
  548. }
  549. /**
  550. * Applies a new Paint object.
  551. * @param paint Paint object to use
  552. * @param fill True if to be applied for filling
  553. */
  554. protected void applyPaint(Paint paint, boolean fill) {
  555. preparePainting();
  556. if (paint instanceof GradientPaint) {
  557. log.warn("NYI: Gradient paint");
  558. } else if (paint instanceof TexturePaint) {
  559. log.warn("NYI: texture paint");
  560. }
  561. }
  562. /**
  563. * Applies a new Stroke object.
  564. * @param stroke Stroke object to use
  565. */
  566. protected void applyStroke(Stroke stroke) {
  567. preparePainting();
  568. try {
  569. if (stroke instanceof BasicStroke) {
  570. BasicStroke bs = (BasicStroke)stroke;
  571. float[] da = bs.getDashArray();
  572. if (da != null) {
  573. gen.write("[");
  574. for (int count = 0; count < da.length; count++) {
  575. gen.write("" + ((int)da[count]));
  576. if (count < da.length - 1) {
  577. gen.write(" ");
  578. }
  579. }
  580. gen.write("] ");
  581. float offset = bs.getDashPhase();
  582. gen.writeln(((int)offset) + " setdash");
  583. }
  584. int ec = bs.getEndCap();
  585. switch (ec) {
  586. case BasicStroke.CAP_BUTT:
  587. gen.writeln("0 setlinecap");
  588. break;
  589. case BasicStroke.CAP_ROUND:
  590. gen.writeln("1 setlinecap");
  591. break;
  592. case BasicStroke.CAP_SQUARE:
  593. gen.writeln("2 setlinecap");
  594. break;
  595. default: log.warn("Unsupported line cap: " + ec);
  596. }
  597. int lj = bs.getLineJoin();
  598. switch (lj) {
  599. case BasicStroke.JOIN_MITER:
  600. gen.writeln("0 setlinejoin");
  601. break;
  602. case BasicStroke.JOIN_ROUND:
  603. gen.writeln("1 setlinejoin");
  604. break;
  605. case BasicStroke.JOIN_BEVEL:
  606. gen.writeln("2 setlinejoin");
  607. break;
  608. default: log.warn("Unsupported line join: " + lj);
  609. }
  610. float lw = bs.getLineWidth();
  611. gen.writeln(gen.formatDouble(lw) + " setlinewidth");
  612. float ml = bs.getMiterLimit();
  613. gen.writeln(gen.formatDouble(ml) + " setmiterlimit");
  614. }
  615. } catch (IOException ioe) {
  616. handleIOException(ioe);
  617. }
  618. }
  619. /**
  620. * Renders a {@link RenderedImage},
  621. * applying a transform from image
  622. * space into user space before drawing.
  623. * The transformation from user space into device space is done with
  624. * the current <code>Transform</code> in the <code>Graphics2D</code>.
  625. * The specified transformation is applied to the image before the
  626. * transform attribute in the <code>Graphics2D</code> context is applied.
  627. * The rendering attributes applied include the <code>Clip</code>,
  628. * <code>Transform</code>, and <code>Composite</code> attributes. Note
  629. * that no rendering is done if the specified transform is
  630. * noninvertible.
  631. * @param img the image to be rendered
  632. * @param xform the transformation from image space into user space
  633. * @see #transform
  634. * @see #setTransform
  635. * @see #setComposite
  636. * @see #clip
  637. * @see #setClip
  638. */
  639. public void drawRenderedImage(RenderedImage img, AffineTransform xform) {
  640. preparePainting();
  641. log.warn("NYI: drawRenderedImage");
  642. }
  643. /**
  644. * Renders a
  645. * {@link RenderableImage},
  646. * applying a transform from image space into user space before drawing.
  647. * The transformation from user space into device space is done with
  648. * the current <code>Transform</code> in the <code>Graphics2D</code>.
  649. * The specified transformation is applied to the image before the
  650. * transform attribute in the <code>Graphics2D</code> context is applied.
  651. * The rendering attributes applied include the <code>Clip</code>,
  652. * <code>Transform</code>, and <code>Composite</code> attributes. Note
  653. * that no rendering is done if the specified transform is
  654. * noninvertible.
  655. * <p>
  656. * Rendering hints set on the <code>Graphics2D</code> object might
  657. * be used in rendering the <code>RenderableImage</code>.
  658. * If explicit control is required over specific hints recognized by a
  659. * specific <code>RenderableImage</code>, or if knowledge of which hints
  660. * are used is required, then a <code>RenderedImage</code> should be
  661. * obtained directly from the <code>RenderableImage</code>
  662. * and rendered using
  663. * {@link #drawRenderedImage(RenderedImage, AffineTransform) drawRenderedImage}.
  664. * @param img the image to be rendered
  665. * @param xform the transformation from image space into user space
  666. * @see #transform
  667. * @see #setTransform
  668. * @see #setComposite
  669. * @see #clip
  670. * @see #setClip
  671. * @see #drawRenderedImage
  672. */
  673. public void drawRenderableImage(RenderableImage img,
  674. AffineTransform xform) {
  675. preparePainting();
  676. log.warn("NYI: drawRenderableImage");
  677. }
  678. /**
  679. * Establishes the given color in the PostScript interpreter.
  680. * @param c the color to set
  681. * @throws IOException In case of an I/O problem
  682. */
  683. protected void establishColor(Color c) throws IOException {
  684. StringBuffer p = new StringBuffer();
  685. float[] comps = c.getColorComponents(null);
  686. if (c.getColorSpace().getType() == ColorSpace.TYPE_RGB) {
  687. // according to pdfspec 12.1 p.399
  688. // if the colors are the same then just use the g or G operator
  689. boolean same = (comps[0] == comps[1]
  690. && comps[0] == comps[2]);
  691. // output RGB
  692. if (same) {
  693. p.append(gen.formatDouble(comps[0]));
  694. } else {
  695. for (int i = 0; i < c.getColorSpace().getNumComponents(); i++) {
  696. if (i > 0) {
  697. p.append(" ");
  698. }
  699. p.append(gen.formatDouble(comps[i]));
  700. }
  701. }
  702. if (same) {
  703. p.append(" setgray");
  704. } else {
  705. p.append(" setrgbcolor");
  706. }
  707. } else if (c.getColorSpace().getType() == ColorSpace.TYPE_CMYK) {
  708. // colorspace is CMYK
  709. for (int i = 0; i < c.getColorSpace().getNumComponents(); i++) {
  710. if (i > 0) {
  711. p.append(" ");
  712. }
  713. p.append(gen.formatDouble(comps[i]));
  714. }
  715. p.append(" setcmykcolor");
  716. } else {
  717. // means we're in DeviceGray or Unknown.
  718. // assume we're in DeviceGray, because otherwise we're screwed.
  719. p.append(gen.formatDouble(comps[0]));
  720. p.append(" setgray");
  721. }
  722. gen.writeln(p.toString());
  723. }
  724. /**
  725. * Renders the text specified by the specified <code>String</code>,
  726. * using the current <code>Font</code> and <code>Paint</code> attributes
  727. * in the <code>Graphics2D</code> context.
  728. * The baseline of the first character is at position
  729. * (<i>x</i>,&nbsp;<i>y</i>) in the User Space.
  730. * The rendering attributes applied include the <code>Clip</code>,
  731. * <code>Transform</code>, <code>Paint</code>, <code>Font</code> and
  732. * <code>Composite</code> attributes. For characters in script systems
  733. * such as Hebrew and Arabic, the glyphs can be rendered from right to
  734. * left, in which case the coordinate supplied is the location of the
  735. * leftmost character on the baseline.
  736. * @param s the <code>String</code> to be rendered
  737. * @param x the x-coordinate where the <code>String</code>
  738. * should be rendered
  739. * @param y the y-coordinate where the <code>String</code>
  740. * should be rendered
  741. * @see #setPaint
  742. * @see java.awt.Graphics#setColor
  743. * @see java.awt.Graphics#setFont
  744. * @see #setTransform
  745. * @see #setComposite
  746. * @see #setClip
  747. */
  748. public void drawString(String s, float x, float y) {
  749. if (this.textAsShapes) {
  750. drawStringAsShapes(s, x, y);
  751. } else {
  752. drawStringAsText(s, x, y);
  753. }
  754. }
  755. /**
  756. * Draw a string to the PostScript document. The text is painted as shapes.
  757. * @param s the string to draw
  758. * @param x the x position
  759. * @param y the y position
  760. */
  761. public void drawStringAsShapes(String s, float x, float y) {
  762. java.awt.Font awtFont = super.getFont();
  763. FontRenderContext frc = super.getFontRenderContext();
  764. GlyphVector gv = awtFont.createGlyphVector(frc, s);
  765. Shape glyphOutline = gv.getOutline(x, y);
  766. fill(glyphOutline);
  767. }
  768. /**
  769. * Draw a string to the PostScript document. The text is painted using
  770. * text operations.
  771. * @param s the string to draw
  772. * @param x the x position
  773. * @param y the y position
  774. */
  775. public void drawStringAsText(String s, float x, float y) {
  776. preparePainting();
  777. log.trace("drawString('" + s + "', " + x + ", " + y + ")");
  778. try {
  779. if (this.overrideFont == null) {
  780. java.awt.Font awtFont = getFont();
  781. this.font = createFont(awtFont);
  782. } else {
  783. this.font = this.overrideFont;
  784. this.overrideFont = null;
  785. }
  786. //Color and Font state
  787. establishColor(getColor());
  788. establishCurrentFont();
  789. //Clip
  790. Shape imclip = getClip();
  791. writeClip(imclip);
  792. gen.saveGraphicsState();
  793. //Prepare correct transformation
  794. AffineTransform trans = getTransform();
  795. gen.concatMatrix(trans);
  796. gen.writeln(gen.formatDouble(x) + " "
  797. + gen.formatDouble(y) + " moveto ");
  798. gen.writeln("1 -1 scale");
  799. StringBuffer sb = new StringBuffer("(");
  800. escapeText(s, sb);
  801. sb.append(") t ");
  802. gen.writeln(sb.toString());
  803. gen.restoreGraphicsState();
  804. } catch (IOException ioe) {
  805. handleIOException(ioe);
  806. }
  807. }
  808. private void escapeText(final String text, StringBuffer target) {
  809. final int l = text.length();
  810. for (int i = 0; i < l; i++) {
  811. final char ch = text.charAt(i);
  812. final char mch = this.font.mapChar(ch);
  813. PSGenerator.escapeChar(mch, target);
  814. }
  815. }
  816. private Font createFont(java.awt.Font f) {
  817. String fontFamily = f.getFamily();
  818. if (fontFamily.equals("sanserif")) {
  819. fontFamily = "sans-serif";
  820. }
  821. int fontSize = 1000 * f.getSize();
  822. String style = f.isItalic() ? "italic" : "normal";
  823. int weight = f.isBold() ? Font.BOLD : Font.NORMAL;
  824. String fontKey = fontInfo.findAdjustWeight(fontFamily, style, weight);
  825. if (fontKey == null) {
  826. fontKey = fontInfo.findAdjustWeight("sans-serif", style, weight);
  827. }
  828. return new Font(fontKey, fontInfo.getMetricsFor(fontKey), fontSize);
  829. }
  830. private void establishCurrentFont() throws IOException {
  831. if ((currentFontName != this.font.getFontName())
  832. || (currentFontSize != this.font.getFontSize())) {
  833. gen.writeln(this.font.getFontName() + " " + this.font.getFontSize() + " F");
  834. currentFontName = this.font.getFontName();
  835. currentFontSize = this.font.getFontSize();
  836. }
  837. }
  838. /**
  839. * Renders the text of the specified iterator, using the
  840. * <code>Graphics2D</code> context's current <code>Paint</code>. The
  841. * iterator must specify a font
  842. * for each character. The baseline of the
  843. * first character is at position (<i>x</i>,&nbsp;<i>y</i>) in the
  844. * User Space.
  845. * The rendering attributes applied include the <code>Clip</code>,
  846. * <code>Transform</code>, <code>Paint</code>, and
  847. * <code>Composite</code> attributes.
  848. * For characters in script systems such as Hebrew and Arabic,
  849. * the glyphs can be rendered from right to left, in which case the
  850. * coordinate supplied is the location of the leftmost character
  851. * on the baseline.
  852. * @param iterator the iterator whose text is to be rendered
  853. * @param x the x-coordinate where the iterator's text is to be
  854. * rendered
  855. * @param y the y-coordinate where the iterator's text is to be
  856. * rendered
  857. * @see #setPaint
  858. * @see java.awt.Graphics#setColor
  859. * @see #setTransform
  860. * @see #setComposite
  861. * @see #setClip
  862. */
  863. public void drawString(AttributedCharacterIterator iterator, float x,
  864. float y) {
  865. preparePainting();
  866. log.warn("NYI: drawString(AttributedCharacterIterator)");
  867. /*
  868. try {
  869. gen.writeln("BT");
  870. Shape imclip = getClip();
  871. writeClip(imclip);
  872. establishColor(getColor());
  873. AffineTransform trans = getTransform();
  874. trans.translate(x, y);
  875. double[] vals = new double[6];
  876. trans.getMatrix(vals);
  877. for (char ch = iterator.first(); ch != CharacterIterator.DONE;
  878. ch = iterator.next()) {
  879. //Map attr = iterator.getAttributes();
  880. gen.writeln(gen.formatDouble(vals[0]) + " "
  881. + gen.formatDouble(vals[1]) + " "
  882. + gen.formatDouble(vals[2]) + " "
  883. + gen.formatDouble(vals[3]) + " "
  884. + gen.formatDouble(vals[4]) + " "
  885. + gen.formatDouble(vals[5]) + " "
  886. + gen.formatDouble(vals[6]) + " Tm [" + ch
  887. + "]");
  888. }
  889. gen.writeln("ET");
  890. } catch (IOException ioe) {
  891. handleIOException(ioe);
  892. }*/
  893. }
  894. /**
  895. * Fills the interior of a <code>Shape</code> using the settings of the
  896. * <code>Graphics2D</code> context. The rendering attributes applied
  897. * include the <code>Clip</code>, <code>Transform</code>,
  898. * <code>Paint</code>, and <code>Composite</code>.
  899. * @param s the <code>Shape</code> to be filled
  900. * @see #setPaint
  901. * @see java.awt.Graphics#setColor
  902. * @see #transform
  903. * @see #setTransform
  904. * @see #setComposite
  905. * @see #clip
  906. * @see #setClip
  907. */
  908. public void fill(Shape s) {
  909. preparePainting();
  910. try {
  911. gen.saveGraphicsState();
  912. AffineTransform trans = getTransform();
  913. boolean newTransform = gen.getCurrentState().checkTransform(trans)
  914. && !trans.isIdentity();
  915. if (newTransform) {
  916. gen.concatMatrix(trans);
  917. }
  918. Shape imclip = getClip();
  919. writeClip(imclip);
  920. establishColor(getColor());
  921. applyPaint(getPaint(), true);
  922. gen.writeln("newpath");
  923. PathIterator iter = s.getPathIterator(IDENTITY_TRANSFORM);
  924. processPathIterator(iter);
  925. doDrawing(true, false,
  926. iter.getWindingRule() == PathIterator.WIND_EVEN_ODD);
  927. gen.restoreGraphicsState();
  928. } catch (IOException ioe) {
  929. handleIOException(ioe);
  930. }
  931. }
  932. /**
  933. * Commits a painting operation.
  934. * @param fill filling
  935. * @param stroke stroking
  936. * @param nonzero true if the non-zero winding rule should be used when filling
  937. * @exception IOException In case of an I/O problem
  938. */
  939. protected void doDrawing(boolean fill, boolean stroke, boolean nonzero)
  940. throws IOException {
  941. preparePainting();
  942. if (fill) {
  943. if (stroke) {
  944. if (!nonzero) {
  945. gen.writeln("gsave fill grestore stroke");
  946. } else {
  947. gen.writeln("gsave eofill grestore stroke");
  948. }
  949. } else {
  950. if (!nonzero) {
  951. gen.writeln("fill");
  952. } else {
  953. gen.writeln("eofill");
  954. }
  955. }
  956. } else {
  957. // if(stroke)
  958. gen.writeln("stroke");
  959. }
  960. }
  961. /**
  962. * Returns the device configuration associated with this
  963. * <code>Graphics2D</code>.
  964. * @return the device configuration
  965. */
  966. public GraphicsConfiguration getDeviceConfiguration() {
  967. return GraphicsEnvironment.getLocalGraphicsEnvironment().
  968. getDefaultScreenDevice().getDefaultConfiguration();
  969. }
  970. /**
  971. * Used to create proper font metrics
  972. */
  973. private Graphics2D fmg;
  974. {
  975. BufferedImage bi = new BufferedImage(1, 1,
  976. BufferedImage.TYPE_INT_ARGB);
  977. fmg = bi.createGraphics();
  978. }
  979. /**
  980. * Sets the overriding font.
  981. * @param font Font to set
  982. */
  983. public void setOverrideFont(Font font) {
  984. this.overrideFont = font;
  985. }
  986. /**
  987. * Gets the font metrics for the specified font.
  988. * @return the font metrics for the specified font.
  989. * @param f the specified font
  990. * @see java.awt.Graphics#getFont
  991. * @see java.awt.FontMetrics
  992. * @see java.awt.Graphics#getFontMetrics()
  993. */
  994. public java.awt.FontMetrics getFontMetrics(java.awt.Font f) {
  995. return fmg.getFontMetrics(f);
  996. }
  997. /**
  998. * Sets the paint mode of this graphics context to alternate between
  999. * this graphics context's current color and the new specified color.
  1000. * This specifies that logical pixel operations are performed in the
  1001. * XOR mode, which alternates pixels between the current color and
  1002. * a specified XOR color.
  1003. * <p>
  1004. * When drawing operations are performed, pixels which are the
  1005. * current color are changed to the specified color, and vice versa.
  1006. * <p>
  1007. * Pixels that are of colors other than those two colors are changed
  1008. * in an unpredictable but reversible manner; if the same figure is
  1009. * drawn twice, then all pixels are restored to their original values.
  1010. * @param c1 the XOR alternation color
  1011. */
  1012. public void setXORMode(Color c1) {
  1013. log.warn("NYI: setXORMode");
  1014. }
  1015. /**
  1016. * Copies an area of the component by a distance specified by
  1017. * <code>dx</code> and <code>dy</code>. From the point specified
  1018. * by <code>x</code> and <code>y</code>, this method
  1019. * copies downwards and to the right. To copy an area of the
  1020. * component to the left or upwards, specify a negative value for
  1021. * <code>dx</code> or <code>dy</code>.
  1022. * If a portion of the source rectangle lies outside the bounds
  1023. * of the component, or is obscured by another window or component,
  1024. * <code>copyArea</code> will be unable to copy the associated
  1025. * pixels. The area that is omitted can be refreshed by calling
  1026. * the component's <code>paint</code> method.
  1027. * @param x the <i>x</i> coordinate of the source rectangle.
  1028. * @param y the <i>y</i> coordinate of the source rectangle.
  1029. * @param width the width of the source rectangle.
  1030. * @param height the height of the source rectangle.
  1031. * @param dx the horizontal distance to copy the pixels.
  1032. * @param dy the vertical distance to copy the pixels.
  1033. */
  1034. public void copyArea(int x, int y, int width, int height, int dx,
  1035. int dy) {
  1036. log.warn("NYI: copyArea");
  1037. }
  1038. /* --- for debugging
  1039. public void transform(AffineTransform tx) {
  1040. System.out.println("transform(" + toArray(tx) + ")");
  1041. super.transform(zx);
  1042. }
  1043. public void scale(double sx, double sy) {
  1044. System.out.println("scale(" + sx + ", " + sy + ")");
  1045. super.scale(sx, sy);
  1046. }
  1047. public void translate(double tx, double ty) {
  1048. System.out.println("translate(double " + tx + ", " + ty + ")");
  1049. super.translate(tx, ty);
  1050. }
  1051. public void translate(int tx, int ty) {
  1052. System.out.println("translate(int " + tx + ", " + ty + ")");
  1053. super.translate(tx, ty);
  1054. }
  1055. */
  1056. }