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.

PCLRenderer.java 32KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868
  1. /*
  2. * Copyright 1999-2006 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.pcl;
  18. // FOP
  19. import org.apache.fop.apps.FOPException;
  20. import org.apache.fop.apps.MimeConstants;
  21. import org.apache.fop.area.Area;
  22. import org.apache.fop.area.Block;
  23. import org.apache.fop.area.BlockViewport;
  24. import org.apache.fop.area.CTM;
  25. import org.apache.fop.area.PageViewport;
  26. import org.apache.fop.area.Trait;
  27. import org.apache.fop.area.Trait.Color;
  28. import org.apache.fop.area.inline.AbstractTextArea;
  29. import org.apache.fop.area.inline.ForeignObject;
  30. import org.apache.fop.area.inline.Image;
  31. import org.apache.fop.area.inline.SpaceArea;
  32. import org.apache.fop.area.inline.TextArea;
  33. import org.apache.fop.area.inline.Viewport;
  34. import org.apache.fop.area.inline.WordArea;
  35. import org.apache.fop.fonts.Font;
  36. import org.apache.fop.image.EPSImage;
  37. import org.apache.fop.image.FopImage;
  38. import org.apache.fop.image.ImageFactory;
  39. import org.apache.fop.image.XMLImage;
  40. import org.apache.fop.render.Graphics2DAdapter;
  41. import org.apache.fop.render.PrintRenderer;
  42. import org.apache.fop.render.RendererContext;
  43. import org.apache.fop.render.RendererContextConstants;
  44. import org.apache.fop.traits.BorderProps;
  45. import org.apache.xmlgraphics.java2d.GraphicContext;
  46. import org.w3c.dom.Document;
  47. // Java
  48. import java.awt.Rectangle;
  49. import java.awt.color.ColorSpace;
  50. import java.awt.geom.AffineTransform;
  51. import java.awt.geom.Point2D;
  52. import java.awt.geom.Rectangle2D;
  53. import java.awt.image.BufferedImage;
  54. import java.awt.image.ColorModel;
  55. import java.awt.image.ComponentColorModel;
  56. import java.awt.image.DataBuffer;
  57. import java.awt.image.DataBufferByte;
  58. import java.awt.image.PixelInterleavedSampleModel;
  59. import java.awt.image.Raster;
  60. import java.awt.image.RenderedImage;
  61. import java.awt.image.SampleModel;
  62. import java.awt.image.WritableRaster;
  63. import java.io.IOException;
  64. import java.io.OutputStream;
  65. import java.util.List;
  66. import java.util.Map;
  67. import java.util.Stack;
  68. /**
  69. * Renderer for the PCL 5 printer language. It also uses HP GL/2 for certain graphic elements.
  70. */
  71. public class PCLRenderer extends PrintRenderer {
  72. /** The MIME type for PCL */
  73. public static final String MIME_TYPE = MimeConstants.MIME_PCL_ALT;
  74. /** The OutputStream to write the PCL stream to */
  75. protected OutputStream out;
  76. /** The PCL generator */
  77. protected PCLGenerator gen;
  78. private boolean ioTrouble = false;
  79. private Stack graphicContextStack = new Stack();
  80. private GraphicContext graphicContext = new GraphicContext();
  81. /**
  82. * Create the PCL renderer
  83. */
  84. public PCLRenderer() {
  85. }
  86. /**
  87. * Central exception handler for I/O exceptions.
  88. * @param ioe IOException to handle
  89. */
  90. protected void handleIOTrouble(IOException ioe) {
  91. if (!ioTrouble) {
  92. log.error("Error while writing to target file", ioe);
  93. ioTrouble = true;
  94. }
  95. }
  96. /** @see org.apache.fop.render.Renderer#getGraphics2DAdapter() */
  97. public Graphics2DAdapter getGraphics2DAdapter() {
  98. return new PCLGraphics2DAdapter();
  99. }
  100. /** @return the GraphicContext used to track coordinate system transformations */
  101. public GraphicContext getGraphicContext() {
  102. return this.graphicContext;
  103. }
  104. /**
  105. * Sets the current font (NOTE: Hard-coded font mappings ATM!)
  106. * @param name the font name (internal F* names for now)
  107. * @param size the font size
  108. * @throws IOException if an I/O problem occurs
  109. */
  110. public void setFont(String name, float size) throws IOException {
  111. int fontcode = 0;
  112. if (name.length() > 1 && name.charAt(0) == 'F') {
  113. try {
  114. fontcode = Integer.parseInt(name.substring(1));
  115. } catch (Exception e) {
  116. log.error(e);
  117. }
  118. }
  119. String formattedSize = gen.formatDouble2(size / 1000);
  120. switch (fontcode) {
  121. case 1: // F1 = Helvetica
  122. // gen.writeCommand("(8U");
  123. // gen.writeCommand("(s1p" + formattedSize + "v0s0b24580T");
  124. // Arial is more common among PCL5 printers than Helvetica - so use Arial
  125. gen.writeCommand("(0N");
  126. gen.writeCommand("(s1p" + formattedSize + "v0s0b16602T");
  127. break;
  128. case 2: // F2 = Helvetica Oblique
  129. gen.writeCommand("(0N");
  130. gen.writeCommand("(s1p" + formattedSize + "v1s0b16602T");
  131. break;
  132. case 3: // F3 = Helvetica Bold
  133. gen.writeCommand("(0N");
  134. gen.writeCommand("(s1p" + formattedSize + "v0s3b16602T");
  135. break;
  136. case 4: // F4 = Helvetica Bold Oblique
  137. gen.writeCommand("(0N");
  138. gen.writeCommand("(s1p" + formattedSize + "v1s3b16602T");
  139. break;
  140. case 5: // F5 = Times Roman
  141. // gen.writeCommand("(8U");
  142. // gen.writeCommand("(s1p" + formattedSize + "v0s0b25093T");
  143. // Times New is more common among PCL5 printers than Times - so use Times New
  144. gen.writeCommand("(0N");
  145. gen.writeCommand("(s1p" + formattedSize + "v0s0b16901T");
  146. break;
  147. case 6: // F6 = Times Italic
  148. gen.writeCommand("(0N");
  149. gen.writeCommand("(s1p" + formattedSize + "v1s0b16901T");
  150. break;
  151. case 7: // F7 = Times Bold
  152. gen.writeCommand("(0N");
  153. gen.writeCommand("(s1p" + formattedSize + "v0s3b16901T");
  154. break;
  155. case 8: // F8 = Times Bold Italic
  156. gen.writeCommand("(0N");
  157. gen.writeCommand("(s1p" + formattedSize + "v1s3b16901T");
  158. break;
  159. case 9: // F9 = Courier
  160. gen.writeCommand("(0N");
  161. gen.writeCommand("(s0p" + gen.formatDouble2(120.01f / (size / 1000.00f))
  162. + "h0s0b4099T");
  163. break;
  164. case 10: // F10 = Courier Oblique
  165. gen.writeCommand("(0N");
  166. gen.writeCommand("(s0p" + gen.formatDouble2(120.01f / (size / 1000.00f))
  167. + "h1s0b4099T");
  168. break;
  169. case 11: // F11 = Courier Bold
  170. gen.writeCommand("(0N");
  171. gen.writeCommand("(s0p" + gen.formatDouble2(120.01f / (size / 1000.00f))
  172. + "h0s3b4099T");
  173. break;
  174. case 12: // F12 = Courier Bold Oblique
  175. gen.writeCommand("(0N");
  176. gen.writeCommand("(s0p" + gen.formatDouble2(120.01f / (size / 1000.00f))
  177. + "h1s3b4099T");
  178. break;
  179. case 13: // F13 = Symbol
  180. gen.writeCommand("(19M");
  181. gen.writeCommand("(s1p" + formattedSize + "v0s0b16686T");
  182. // ECMA Latin 1 Symbol Set in Times Roman???
  183. // gen.writeCommand("(9U");
  184. // gen.writeCommand("(s1p" + formattedSize + "v0s0b25093T");
  185. break;
  186. case 14: // F14 = Zapf Dingbats
  187. gen.writeCommand("(14L");
  188. gen.writeCommand("(s1p" + formattedSize + "v0s0b45101T");
  189. break;
  190. default:
  191. gen.writeCommand("(0N");
  192. gen.writeCommand("(s" + formattedSize + "V");
  193. break;
  194. }
  195. }
  196. /** @see org.apache.fop.render.Renderer#startRenderer(java.io.OutputStream) */
  197. public void startRenderer(OutputStream outputStream) throws IOException {
  198. log.debug("Rendering areas to PCL...");
  199. this.out = outputStream;
  200. this.gen = new PCLGenerator(out);
  201. gen.universalEndOfLanguage();
  202. gen.resetPrinter();
  203. }
  204. /** @see org.apache.fop.render.Renderer#stopRenderer() */
  205. public void stopRenderer() throws IOException {
  206. gen.separateJobs();
  207. gen.resetPrinter();
  208. gen.universalEndOfLanguage();
  209. }
  210. /** @see org.apache.fop.render.AbstractRenderer */
  211. public String getMimeType() {
  212. return MIME_TYPE;
  213. }
  214. /**
  215. * @see org.apache.fop.render.AbstractRenderer#renderPage(org.apache.fop.area.PageViewport)
  216. */
  217. public void renderPage(PageViewport page) throws IOException, FOPException {
  218. saveGraphicsState();
  219. final long pagewidth = Math.round(page.getViewArea().getWidth());
  220. final long pageheight = Math.round(page.getViewArea().getHeight());
  221. selectPageFormat(pagewidth, pageheight);
  222. if (false) { //TODO DEBUG CODE! Remove me.
  223. //gen.fillRect(0, 0, (int)pagewidth, (int)pageheight, java.awt.Color.yellow);
  224. //gen.fillRect(5000, 5000, (int)pagewidth - 10000, (int)pageheight - 10000, java.awt.Color.yellow);
  225. //gen.fillRect(10000, 10000, (int)pagewidth / 4 - 20000, (int)pageheight / 4 - 20000, java.awt.Color.red);
  226. for (int i = 0; i < 29; i++) {
  227. if (i % 2 == 0) {
  228. int w = (int)(10 * 2.835 * 1000);
  229. Point2D p = transformedPoint(i * w, 0);
  230. gen.fillRect((int)p.getX(), (int)p.getY(), w, w, java.awt.Color.yellow);
  231. }
  232. }
  233. }
  234. super.renderPage(page);
  235. gen.formFeed();
  236. restoreGraphicsState();
  237. }
  238. private void selectPageFormat(long pagewidth, long pageheight) throws IOException {
  239. PCLPageDefinition pageDef = PCLPageDefinition.getPageDefinition(
  240. pagewidth, pageheight, 1000);
  241. if (pageDef != null) {
  242. // Adjust for the offset into the logical page
  243. graphicContext.translate(-pageDef.getLogicalPageXOffset(), 0);
  244. if (pageDef.isLandscapeFormat()) {
  245. gen.writeCommand("&l1O"); //Orientation
  246. } else {
  247. gen.writeCommand("&l0O"); //Orientation
  248. }
  249. } else {
  250. // Adjust for the offset into the logical page
  251. // X Offset to allow for PCL implicit 1/4" left margin (= 180 decipoints)
  252. graphicContext.translate(-18000, 18000);
  253. gen.writeCommand("&l0O"); //Orientation
  254. }
  255. gen.clearHorizontalMargins();
  256. gen.setTopMargin(0);
  257. }
  258. /** Saves the current graphics state on the stack. */
  259. protected void saveGraphicsState() {
  260. graphicContextStack.push(graphicContext);
  261. graphicContext = (GraphicContext)graphicContext.clone();
  262. }
  263. /** Restores the last graphics state from the stack. */
  264. protected void restoreGraphicsState() {
  265. graphicContext = (GraphicContext)graphicContextStack.pop();
  266. }
  267. /**
  268. * Clip an area. write a clipping operation given coordinates in the current
  269. * transform. Coordinates are in points.
  270. *
  271. * @param x the x coordinate
  272. * @param y the y coordinate
  273. * @param width the width of the area
  274. * @param height the height of the area
  275. */
  276. protected void clipRect(float x, float y, float width, float height) {
  277. //PCL cannot clip (only HP GL/2 can)
  278. }
  279. /**
  280. * @see org.apache.fop.render.AbstractRenderer#startVParea(CTM, Rectangle2D)
  281. */
  282. protected void startVParea(CTM ctm, Rectangle2D clippingRect) {
  283. saveGraphicsState();
  284. AffineTransform at = new AffineTransform(ctm.toArray());
  285. log.debug("startVPArea: " + at);
  286. graphicContext.transform(at);
  287. }
  288. /**
  289. * @see org.apache.fop.render.AbstractRenderer#endVParea()
  290. */
  291. protected void endVParea() {
  292. restoreGraphicsState();
  293. }
  294. /**
  295. * Handle block traits.
  296. * The block could be any sort of block with any positioning
  297. * so this should render the traits such as border and background
  298. * in its position.
  299. *
  300. * @param block the block to render the traits
  301. */
  302. protected void handleBlockTraits(Block block) {
  303. int borderPaddingStart = block.getBorderAndPaddingWidthStart();
  304. int borderPaddingBefore = block.getBorderAndPaddingWidthBefore();
  305. float startx = currentIPPosition / 1000f;
  306. float starty = currentBPPosition / 1000f;
  307. float width = block.getIPD() / 1000f;
  308. float height = block.getBPD() / 1000f;
  309. startx += block.getStartIndent() / 1000f;
  310. startx -= block.getBorderAndPaddingWidthStart() / 1000f;
  311. width += borderPaddingStart / 1000f;
  312. width += block.getBorderAndPaddingWidthEnd() / 1000f;
  313. height += borderPaddingBefore / 1000f;
  314. height += block.getBorderAndPaddingWidthAfter() / 1000f;
  315. drawBackAndBorders(block, startx, starty, width, height);
  316. }
  317. /**
  318. * @see org.apache.fop.render.AbstractRenderer#renderText(TextArea)
  319. */
  320. protected void renderText(TextArea area) {
  321. //renderInlineAreaBackAndBorders(area);
  322. String fontname = getInternalFontNameForArea(area);
  323. int fontsize = area.getTraitAsInteger(Trait.FONT_SIZE);
  324. //Determine position
  325. //int saveIP = currentIPPosition;
  326. //int saveBP = currentBPPosition;
  327. int rx = currentIPPosition + area.getBorderAndPaddingWidthStart();
  328. int bl = currentBPPosition + area.getOffset() + area.getBaselineOffset();
  329. try {
  330. setFont(fontname, fontsize);
  331. Color col = (Color)area.getTrait(Trait.COLOR);
  332. //this.currentFill = col;
  333. if (col != null) {
  334. //useColor(ct);
  335. gen.setPatternTransparencyMode(false);
  336. gen.selectCurrentPattern(gen.convertToPCLShade(col.getAWTColor()), 2);
  337. }
  338. saveGraphicsState();
  339. updatePrintDirection();
  340. graphicContext.translate(rx, bl);
  341. moveTo(0, 0);
  342. super.renderText(area); //Updates IPD
  343. //renderTextDecoration(tf, fontsize, area, bl, rx);
  344. restoreGraphicsState();
  345. } catch (IOException ioe) {
  346. handleIOTrouble(ioe);
  347. }
  348. }
  349. void moveTo(int x, int y) throws IOException {
  350. Point2D transPoint = transformedPoint(x, y);
  351. gen.writeCommand("&a" + gen.formatDouble2(transPoint.getX() / 100) + "h"
  352. + gen.formatDouble2(transPoint.getY() / 100) + "V");
  353. }
  354. private void updatePrintDirection() throws IOException {
  355. AffineTransform at = graphicContext.getTransform();
  356. if (log.isDebugEnabled()) {
  357. log.debug(at.getScaleX() + " " + at.getScaleY() + " "
  358. + at.getShearX() + " " + at.getShearY() );
  359. }
  360. if (at.getScaleX() == 0 && at.getScaleY() == 0
  361. && at.getShearX() == 1 && at.getShearY() == -1) {
  362. gen.writeCommand("&a90P");
  363. } else if (at.getScaleX() == -1 && at.getScaleY() == -1
  364. && at.getShearX() == 0 && at.getShearY() == 0) {
  365. gen.writeCommand("&a180P");
  366. } else if (at.getScaleX() == 0 && at.getScaleY() == 0
  367. && at.getShearX() == -1 && at.getShearY() == 1) {
  368. gen.writeCommand("&a270P");
  369. } else {
  370. gen.writeCommand("&a0P");
  371. }
  372. }
  373. private Point2D transformedPoint(float x, float y) {
  374. return transformedPoint(Math.round(x), Math.round(y));
  375. }
  376. private Point2D transformedPoint(int x, int y) {
  377. AffineTransform at = graphicContext.getTransform();
  378. if (log.isDebugEnabled()) {
  379. log.debug("Current transform: " + at);
  380. }
  381. Point2D orgPoint = new Point2D.Float(x, y);
  382. Point2D transPoint = new Point2D.Float();
  383. at.transform(orgPoint, transPoint);
  384. return transPoint;
  385. }
  386. /**
  387. * @see org.apache.fop.render.AbstractRenderer#renderWord(org.apache.fop.area.inline.WordArea)
  388. */
  389. protected void renderWord(WordArea word) {
  390. //Font font = getFontFromArea(word.getParentArea());
  391. String s = word.getWord();
  392. try {
  393. gen.writeText(s);
  394. } catch (IOException ioe) {
  395. handleIOTrouble(ioe);
  396. }
  397. super.renderWord(word);
  398. }
  399. /**
  400. * @see org.apache.fop.render.AbstractRenderer#renderSpace(org.apache.fop.area.inline.SpaceArea)
  401. */
  402. protected void renderSpace(SpaceArea space) {
  403. AbstractTextArea textArea = (AbstractTextArea)space.getParentArea();
  404. String s = space.getSpace();
  405. char sp = s.charAt(0);
  406. Font font = getFontFromArea(textArea);
  407. int tws = (space.isAdjustable()
  408. ? ((TextArea) space.getParentArea()).getTextWordSpaceAdjust()
  409. + 2 * textArea.getTextLetterSpaceAdjust()
  410. : 0);
  411. double dx = (font.getCharWidth(sp) + tws) / 100f;
  412. try {
  413. gen.writeCommand("&a+" + gen.formatDouble2(dx) + "H");
  414. } catch (IOException ioe) {
  415. handleIOTrouble(ioe);
  416. }
  417. super.renderSpace(space);
  418. }
  419. /**
  420. * @see org.apache.fop.render.AbstractRenderer#renderViewport(org.apache.fop.area.inline.Viewport)
  421. */
  422. public void renderViewport(Viewport viewport) {
  423. float x = currentIPPosition / 1000f;
  424. float y = (currentBPPosition + viewport.getOffset()) / 1000f;
  425. float width = viewport.getIPD() / 1000f;
  426. float height = viewport.getBPD() / 1000f;
  427. // TODO: Calculate the border rect correctly.
  428. float borderPaddingStart = viewport.getBorderAndPaddingWidthStart() / 1000f;
  429. float borderPaddingBefore = viewport.getBorderAndPaddingWidthBefore() / 1000f;
  430. float bpwidth = borderPaddingStart
  431. + (viewport.getBorderAndPaddingWidthEnd() / 1000f);
  432. float bpheight = borderPaddingBefore
  433. + (viewport.getBorderAndPaddingWidthAfter() / 1000f);
  434. drawBackAndBorders(viewport, x, y, width + bpwidth, height + bpheight);
  435. if (viewport.getClip()) {
  436. saveGraphicsState();
  437. clipRect(x + borderPaddingStart, y + borderPaddingBefore, width, height);
  438. }
  439. super.renderViewport(viewport);
  440. if (viewport.getClip()) {
  441. restoreGraphicsState();
  442. }
  443. }
  444. /**
  445. * @see org.apache.fop.render.AbstractRenderer#renderBlockViewport(BlockViewport, List)
  446. */
  447. protected void renderBlockViewport(BlockViewport bv, List children) {
  448. // clip and position viewport if necessary
  449. // save positions
  450. int saveIP = currentIPPosition;
  451. int saveBP = currentBPPosition;
  452. //String saveFontName = currentFontName;
  453. CTM ctm = bv.getCTM();
  454. int borderPaddingStart = bv.getBorderAndPaddingWidthStart();
  455. int borderPaddingBefore = bv.getBorderAndPaddingWidthBefore();
  456. float x, y;
  457. x = (float)(bv.getXOffset() + containingIPPosition) / 1000f;
  458. y = (float)(bv.getYOffset() + containingBPPosition) / 1000f;
  459. //This is the content-rect
  460. float width = (float)bv.getIPD() / 1000f;
  461. float height = (float)bv.getBPD() / 1000f;
  462. if (bv.getPositioning() == Block.ABSOLUTE
  463. || bv.getPositioning() == Block.FIXED) {
  464. currentIPPosition = bv.getXOffset();
  465. currentBPPosition = bv.getYOffset();
  466. //For FIXED, we need to break out of the current viewports to the
  467. //one established by the page. We save the state stack for restoration
  468. //after the block-container has been painted. See below.
  469. List breakOutList = null;
  470. if (bv.getPositioning() == Block.FIXED) {
  471. //breakOutList = breakOutOfStateStack();
  472. }
  473. CTM tempctm = new CTM(containingIPPosition, containingBPPosition);
  474. ctm = tempctm.multiply(ctm);
  475. //Adjust for spaces (from margin or indirectly by start-indent etc.
  476. x += bv.getSpaceStart() / 1000f;
  477. currentIPPosition += bv.getSpaceStart();
  478. y += bv.getSpaceBefore() / 1000f;
  479. currentBPPosition += bv.getSpaceBefore();
  480. float bpwidth = (borderPaddingStart + bv.getBorderAndPaddingWidthEnd()) / 1000f;
  481. float bpheight = (borderPaddingBefore + bv.getBorderAndPaddingWidthAfter()) / 1000f;
  482. drawBackAndBorders(bv, x, y, width + bpwidth, height + bpheight);
  483. //Now adjust for border/padding
  484. currentIPPosition += borderPaddingStart;
  485. currentBPPosition += borderPaddingBefore;
  486. Rectangle2D clippingRect = null;
  487. if (bv.getClip()) {
  488. clippingRect = new Rectangle(currentIPPosition, currentBPPosition,
  489. bv.getIPD(), bv.getBPD());
  490. }
  491. startVParea(ctm, clippingRect);
  492. currentIPPosition = 0;
  493. currentBPPosition = 0;
  494. renderBlocks(bv, children);
  495. endVParea();
  496. if (breakOutList != null) {
  497. //restoreStateStackAfterBreakOut(breakOutList);
  498. }
  499. currentIPPosition = saveIP;
  500. currentBPPosition = saveBP;
  501. } else {
  502. currentBPPosition += bv.getSpaceBefore();
  503. //borders and background in the old coordinate system
  504. handleBlockTraits(bv);
  505. //Advance to start of content area
  506. currentIPPosition += bv.getStartIndent();
  507. CTM tempctm = new CTM(containingIPPosition, currentBPPosition);
  508. ctm = tempctm.multiply(ctm);
  509. //Now adjust for border/padding
  510. currentBPPosition += borderPaddingBefore;
  511. Rectangle2D clippingRect = null;
  512. if (bv.getClip()) {
  513. clippingRect = new Rectangle(currentIPPosition, currentBPPosition,
  514. bv.getIPD(), bv.getBPD());
  515. }
  516. startVParea(ctm, clippingRect);
  517. currentIPPosition = 0;
  518. currentBPPosition = 0;
  519. renderBlocks(bv, children);
  520. endVParea();
  521. currentIPPosition = saveIP;
  522. currentBPPosition = saveBP;
  523. currentBPPosition += (int)(bv.getAllocBPD());
  524. }
  525. //currentFontName = saveFontName;
  526. }
  527. /**
  528. * @see org.apache.fop.render.AbstractRenderer#renderImage(Image, Rectangle2D)
  529. */
  530. public void renderImage(Image image, Rectangle2D pos) {
  531. String url = ImageFactory.getURL(image.getURL());
  532. ImageFactory fact = userAgent.getFactory().getImageFactory();
  533. FopImage fopimage = fact.getImage(url, userAgent);
  534. if (fopimage == null) {
  535. return;
  536. }
  537. if (!fopimage.load(FopImage.DIMENSIONS)) {
  538. return;
  539. }
  540. String mime = fopimage.getMimeType();
  541. if ("text/xml".equals(mime)) {
  542. if (!fopimage.load(FopImage.ORIGINAL_DATA)) {
  543. return;
  544. }
  545. Document doc = ((XMLImage) fopimage).getDocument();
  546. String ns = ((XMLImage) fopimage).getNameSpace();
  547. renderDocument(doc, ns, pos, image.getForeignAttributes());
  548. } else if ("image/svg+xml".equals(mime)) {
  549. if (!fopimage.load(FopImage.ORIGINAL_DATA)) {
  550. return;
  551. }
  552. Document doc = ((XMLImage) fopimage).getDocument();
  553. String ns = ((XMLImage) fopimage).getNameSpace();
  554. renderDocument(doc, ns, pos, image.getForeignAttributes());
  555. } else if (fopimage instanceof EPSImage) {
  556. log.warn("EPS images are not supported by this renderer");
  557. } else {
  558. if (!fopimage.load(FopImage.BITMAP)) {
  559. log.error("Bitmap image could not be processed: " + fopimage);
  560. return;
  561. }
  562. byte[] imgmap = fopimage.getBitmaps();
  563. ColorModel cm = new ComponentColorModel(
  564. ColorSpace.getInstance(ColorSpace.CS_LINEAR_RGB),
  565. new int[] {8, 8, 8},
  566. false, false,
  567. ColorModel.OPAQUE, DataBuffer.TYPE_BYTE);
  568. int imgw = fopimage.getWidth();
  569. int imgh = fopimage.getHeight();
  570. SampleModel sampleModel = new PixelInterleavedSampleModel(
  571. DataBuffer.TYPE_BYTE, imgw, imgh, 3, imgw * 3, new int[] {0, 1, 2});
  572. DataBuffer dbuf = new DataBufferByte(imgmap, imgw * imgh * 3);
  573. WritableRaster raster = Raster.createWritableRaster(sampleModel,
  574. dbuf, null);
  575. // Combine the color model and raster into a buffered image
  576. RenderedImage img = new BufferedImage(cm, raster, false, null);
  577. try {
  578. moveTo(this.currentIPPosition + (int)pos.getX(),
  579. this.currentBPPosition + (int)pos.getY());
  580. int resolution = (int)Math.round(Math.max(fopimage.getHorizontalResolution(),
  581. fopimage.getVerticalResolution()));
  582. gen.paintBitmap(img, resolution);
  583. } catch (IOException ioe) {
  584. handleIOTrouble(ioe);
  585. }
  586. }
  587. }
  588. /**
  589. * @see org.apache.fop.render.AbstractRenderer#renderForeignObject(ForeignObject, Rectangle2D)
  590. */
  591. public void renderForeignObject(ForeignObject fo, Rectangle2D pos) {
  592. Document doc = fo.getDocument();
  593. String ns = fo.getNameSpace();
  594. renderDocument(doc, ns, pos, fo.getForeignAttributes());
  595. }
  596. /**
  597. * Renders an XML document (SVG for example).
  598. * @param doc the DOM Document containing the XML document to be rendered
  599. * @param ns the namespace URI for the XML document
  600. * @param pos the position for the generated graphic/image
  601. * @param foreignAttributes the foreign attributes containing rendering hints, or null
  602. */
  603. public void renderDocument(Document doc, String ns, Rectangle2D pos, Map foreignAttributes) {
  604. RendererContext context;
  605. context = new RendererContext(this, MIME_TYPE);
  606. context.setUserAgent(userAgent);
  607. context.setProperty(RendererContextConstants.WIDTH,
  608. new Integer((int) pos.getWidth()));
  609. context.setProperty(RendererContextConstants.HEIGHT,
  610. new Integer((int) pos.getHeight()));
  611. context.setProperty(RendererContextConstants.XPOS,
  612. new Integer(currentIPPosition + (int) pos.getX()));
  613. context.setProperty(RendererContextConstants.YPOS,
  614. new Integer(currentBPPosition + (int) pos.getY()));
  615. context.setProperty(RendererContextConstants.PAGE_VIEWPORT,
  616. getCurrentPageViewport());
  617. if (foreignAttributes != null) {
  618. context.setProperty(RendererContextConstants.FOREIGN_ATTRIBUTES, foreignAttributes);
  619. }
  620. renderXML(context, doc, ns);
  621. }
  622. /**
  623. * Draw the background and borders. This draws the background and border
  624. * traits for an area given the position.
  625. *
  626. * @param area the area whose traits are used
  627. * @param startx the start x position
  628. * @param starty the start y position
  629. * @param width the width of the area
  630. * @param height the height of the area
  631. */
  632. protected void drawBackAndBorders(Area area, float startx, float starty,
  633. float width, float height) {
  634. try {
  635. updatePrintDirection();
  636. BorderProps bpsBefore = (BorderProps) area.getTrait(Trait.BORDER_BEFORE);
  637. BorderProps bpsAfter = (BorderProps) area.getTrait(Trait.BORDER_AFTER);
  638. BorderProps bpsStart = (BorderProps) area.getTrait(Trait.BORDER_START);
  639. BorderProps bpsEnd = (BorderProps) area.getTrait(Trait.BORDER_END);
  640. // draw background
  641. Trait.Background back;
  642. back = (Trait.Background) area.getTrait(Trait.BACKGROUND);
  643. if (back != null) {
  644. // Calculate padding rectangle
  645. float sx = startx;
  646. float sy = starty;
  647. float paddRectWidth = width;
  648. float paddRectHeight = height;
  649. if (bpsStart != null) {
  650. sx += bpsStart.width / 1000f;
  651. paddRectWidth -= bpsStart.width / 1000f;
  652. }
  653. if (bpsBefore != null) {
  654. sy += bpsBefore.width / 1000f;
  655. paddRectHeight -= bpsBefore.width / 1000f;
  656. }
  657. if (bpsEnd != null) {
  658. paddRectWidth -= bpsEnd.width / 1000f;
  659. }
  660. if (bpsAfter != null) {
  661. paddRectHeight -= bpsAfter.width / 1000f;
  662. }
  663. if (back.getColor() != null) {
  664. Point2D p = transformedPoint(sx * 1000, sy * 1000);
  665. gen.fillRect((int)p.getX(), (int)p.getY(),
  666. (int)paddRectWidth * 1000, (int)paddRectHeight * 1000,
  667. back.getColor().getAWTColor());
  668. }
  669. // background image
  670. if (back.getFopImage() != null) {
  671. FopImage fopimage = back.getFopImage();
  672. if (fopimage != null && fopimage.load(FopImage.DIMENSIONS)) {
  673. saveGraphicsState();
  674. clipRect(sx, sy, paddRectWidth, paddRectHeight);
  675. int horzCount = (int) ((paddRectWidth * 1000 / fopimage
  676. .getIntrinsicWidth()) + 1.0f);
  677. int vertCount = (int) ((paddRectHeight * 1000 / fopimage
  678. .getIntrinsicHeight()) + 1.0f);
  679. if (back.getRepeat() == EN_NOREPEAT) {
  680. horzCount = 1;
  681. vertCount = 1;
  682. } else if (back.getRepeat() == EN_REPEATX) {
  683. vertCount = 1;
  684. } else if (back.getRepeat() == EN_REPEATY) {
  685. horzCount = 1;
  686. }
  687. // change from points to millipoints
  688. sx *= 1000;
  689. sy *= 1000;
  690. if (horzCount == 1) {
  691. sx += back.getHoriz();
  692. }
  693. if (vertCount == 1) {
  694. sy += back.getVertical();
  695. }
  696. for (int x = 0; x < horzCount; x++) {
  697. for (int y = 0; y < vertCount; y++) {
  698. // place once
  699. Rectangle2D pos;
  700. pos = new Rectangle2D.Float(sx
  701. + (x * fopimage.getIntrinsicWidth()), sy
  702. + (y * fopimage.getIntrinsicHeight()),
  703. fopimage.getIntrinsicWidth(), fopimage
  704. .getIntrinsicHeight());
  705. //putImage(back.getURL(), pos); // TODO test
  706. }
  707. }
  708. restoreGraphicsState();
  709. } else {
  710. log.warn(
  711. "Can't find background image: " + back.getURL());
  712. }
  713. }
  714. }
  715. /*
  716. // draw border
  717. // BORDER_BEFORE
  718. if (bpsBefore != null) {
  719. int borderWidth = (int) Math.round((bpsBefore.width / 1000f));
  720. state.updateColor(bpsBefore.color);
  721. state.getGraph().fillRect((int) startx, (int) starty, (int) width,
  722. borderWidth);
  723. }
  724. // BORDER_AFTER
  725. if (bpsAfter != null) {
  726. int borderWidth = (int) Math.round((bpsAfter.width / 1000f));
  727. float sy = starty + height;
  728. state.updateColor(bpsAfter.color);
  729. state.getGraph().fillRect((int) startx,
  730. (int) (starty + height - borderWidth), (int) width,
  731. borderWidth);
  732. }
  733. // BORDER_START
  734. if (bpsStart != null) {
  735. int borderWidth = (int) Math.round((bpsStart.width / 1000f));
  736. state.updateColor(bpsStart.color);
  737. state.getGraph().fillRect((int) startx, (int) starty, borderWidth,
  738. (int) height);
  739. }
  740. // BORDER_END
  741. if (bpsEnd != null) {
  742. int borderWidth = (int) Math.round((bpsEnd.width / 1000f));
  743. float sx = startx + width;
  744. state.updateColor(bpsEnd.color);
  745. state.getGraph().fillRect((int) (startx + width - borderWidth),
  746. (int) starty, borderWidth, (int) height);
  747. }
  748. */
  749. } catch (IOException ioe) {
  750. handleIOTrouble(ioe);
  751. }
  752. }
  753. }