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.

PSGraphicsPainter.java 14KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386
  1. /*
  2. * Licensed to the Apache Software Foundation (ASF) under one or more
  3. * contributor license agreements. See the NOTICE file distributed with
  4. * this work for additional information regarding copyright ownership.
  5. * The ASF licenses this file to You under the Apache License, Version 2.0
  6. * (the "License"); you may not use this file except in compliance with
  7. * the License. You may obtain a copy of the License at
  8. *
  9. * http://www.apache.org/licenses/LICENSE-2.0
  10. *
  11. * Unless required by applicable law or agreed to in writing, software
  12. * distributed under the License is distributed on an "AS IS" BASIS,
  13. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  14. * See the License for the specific language governing permissions and
  15. * limitations under the License.
  16. */
  17. /* $Id$ */
  18. package org.apache.fop.render.ps;
  19. import java.awt.Color;
  20. import java.awt.Point;
  21. import java.io.IOException;
  22. import org.apache.commons.logging.Log;
  23. import org.apache.commons.logging.LogFactory;
  24. import org.apache.xmlgraphics.ps.PSGenerator;
  25. import org.apache.fop.fo.Constants;
  26. import org.apache.fop.render.intermediate.ArcToBezierCurveTransformer;
  27. import org.apache.fop.render.intermediate.BezierCurvePainter;
  28. import org.apache.fop.render.intermediate.GraphicsPainter;
  29. import org.apache.fop.traits.RuleStyle;
  30. import org.apache.fop.util.ColorUtil;
  31. /**
  32. * PostScript-specific implementation of the {@link BorderPainter}.
  33. */
  34. public class PSGraphicsPainter implements GraphicsPainter, BezierCurvePainter {
  35. /** logging instance */
  36. private static Log log = LogFactory.getLog(PSGraphicsPainter.class);
  37. private final PSGenerator generator;
  38. /** Used for drawing arcs since PS does not natively support drawing elliptic curves */
  39. private final ArcToBezierCurveTransformer arcToBezierCurveTransformer;
  40. /**
  41. * Creates a new border painter for PostScript.
  42. * @param generator the PostScript generator
  43. */
  44. public PSGraphicsPainter(PSGenerator generator) {
  45. this.generator = generator;
  46. this.arcToBezierCurveTransformer = new ArcToBezierCurveTransformer(this);
  47. }
  48. /** {@inheritDoc} */
  49. public void drawBorderLine(int x1, int y1, int x2, int y2, boolean horz,
  50. boolean startOrBefore, int style, Color col) throws IOException {
  51. drawBorderLine(generator, toPoints(x1), toPoints(y1), toPoints(x2), toPoints(y2),
  52. horz, startOrBefore, style, col);
  53. }
  54. private static void drawLine(PSGenerator gen,
  55. float startx, float starty, float endx, float endy) throws IOException {
  56. gen.writeln(gen.formatDouble(startx) + " "
  57. + gen.formatDouble(starty) + " " + gen.mapCommand("moveto") + " "
  58. + gen.formatDouble(endx) + " "
  59. + gen.formatDouble(endy) + " " + gen.mapCommand("lineto") + " "
  60. + gen.mapCommand("stroke") + " " + gen.mapCommand("newpath"));
  61. }
  62. /** {@inheritDoc} */
  63. public static void drawBorderLine(PSGenerator gen,
  64. float x1, float y1, float x2, float y2, boolean horz,
  65. boolean startOrBefore, int style, Color col) throws IOException {
  66. float w = x2 - x1;
  67. float h = y2 - y1;
  68. if ((w < 0) || (h < 0)) {
  69. log.error("Negative extent received. Border won't be painted.");
  70. return;
  71. }
  72. switch (style) {
  73. case Constants.EN_DASHED:
  74. gen.useColor(col);
  75. if (horz) {
  76. float unit = Math.abs(2 * h);
  77. int rep = (int) (w / unit);
  78. if (rep % 2 == 0) {
  79. rep++;
  80. }
  81. unit = w / rep;
  82. gen.useDash("[" + unit + "] 0");
  83. gen.useLineCap(0);
  84. gen.useLineWidth(h);
  85. float ym = y1 + (h / 2);
  86. drawLine(gen, x1, ym, x2, ym);
  87. } else {
  88. float unit = Math.abs(2 * w);
  89. int rep = (int) (h / unit);
  90. if (rep % 2 == 0) {
  91. rep++;
  92. }
  93. unit = h / rep;
  94. gen.useDash("[" + unit + "] 0");
  95. gen.useLineCap(0);
  96. gen.useLineWidth(w);
  97. float xm = x1 + (w / 2);
  98. drawLine(gen, xm, y1, xm, y2);
  99. }
  100. break;
  101. case Constants.EN_DOTTED:
  102. gen.useColor(col);
  103. gen.useLineCap(1); //Rounded!
  104. if (horz) {
  105. float unit = Math.abs(2 * h);
  106. int rep = (int) (w / unit);
  107. if (rep % 2 == 0) {
  108. rep++;
  109. }
  110. unit = w / rep;
  111. gen.useDash("[0 " + unit + "] 0");
  112. gen.useLineWidth(h);
  113. float ym = y1 + (h / 2);
  114. drawLine(gen, x1, ym, x2, ym);
  115. } else {
  116. float unit = Math.abs(2 * w);
  117. int rep = (int) (h / unit);
  118. if (rep % 2 == 0) {
  119. rep++;
  120. }
  121. unit = h / rep;
  122. gen.useDash("[0 " + unit + "] 0");
  123. gen.useLineWidth(w);
  124. float xm = x1 + (w / 2);
  125. drawLine(gen, xm, y1, xm, y2);
  126. }
  127. break;
  128. case Constants.EN_DOUBLE:
  129. gen.useColor(col);
  130. gen.useDash(null);
  131. if (horz) {
  132. float h3 = h / 3;
  133. gen.useLineWidth(h3);
  134. float ym1 = y1 + (h3 / 2);
  135. float ym2 = ym1 + h3 + h3;
  136. drawLine(gen, x1, ym1, x2, ym1);
  137. drawLine(gen, x1, ym2, x2, ym2);
  138. } else {
  139. float w3 = w / 3;
  140. gen.useLineWidth(w3);
  141. float xm1 = x1 + (w3 / 2);
  142. float xm2 = xm1 + w3 + w3;
  143. drawLine(gen, xm1, y1, xm1, y2);
  144. drawLine(gen, xm2, y1, xm2, y2);
  145. }
  146. break;
  147. case Constants.EN_GROOVE:
  148. case Constants.EN_RIDGE:
  149. float colFactor = (style == Constants.EN_GROOVE ? 0.4f : -0.4f);
  150. gen.useDash(null);
  151. if (horz) {
  152. Color uppercol = ColorUtil.lightenColor(col, -colFactor);
  153. Color lowercol = ColorUtil.lightenColor(col, colFactor);
  154. float h3 = h / 3;
  155. gen.useLineWidth(h3);
  156. float ym1 = y1 + (h3 / 2);
  157. gen.useColor(uppercol);
  158. drawLine(gen, x1, ym1, x2, ym1);
  159. gen.useColor(col);
  160. drawLine(gen, x1, ym1 + h3, x2, ym1 + h3);
  161. gen.useColor(lowercol);
  162. drawLine(gen, x1, ym1 + h3 + h3, x2, ym1 + h3 + h3);
  163. } else {
  164. Color leftcol = ColorUtil.lightenColor(col, -colFactor);
  165. Color rightcol = ColorUtil.lightenColor(col, colFactor);
  166. float w3 = w / 3;
  167. gen.useLineWidth(w3);
  168. float xm1 = x1 + (w3 / 2);
  169. gen.useColor(leftcol);
  170. drawLine(gen, xm1, y1, xm1, y2);
  171. gen.useColor(col);
  172. drawLine(gen, xm1 + w3, y1, xm1 + w3, y2);
  173. gen.useColor(rightcol);
  174. drawLine(gen, xm1 + w3 + w3, y1, xm1 + w3 + w3, y2);
  175. }
  176. break;
  177. case Constants.EN_INSET:
  178. case Constants.EN_OUTSET:
  179. colFactor = (style == Constants.EN_OUTSET ? 0.4f : -0.4f);
  180. gen.useDash(null);
  181. if (horz) {
  182. Color c = ColorUtil.lightenColor(col, (startOrBefore ? 1 : -1) * colFactor);
  183. gen.useLineWidth(h);
  184. float ym1 = y1 + (h / 2);
  185. gen.useColor(c);
  186. drawLine(gen, x1, ym1, x2, ym1);
  187. } else {
  188. Color c = ColorUtil.lightenColor(col, (startOrBefore ? 1 : -1) * colFactor);
  189. gen.useLineWidth(w);
  190. float xm1 = x1 + (w / 2);
  191. gen.useColor(c);
  192. drawLine(gen, xm1, y1, xm1, y2);
  193. }
  194. break;
  195. case Constants.EN_HIDDEN:
  196. break;
  197. default:
  198. gen.useColor(col);
  199. gen.useDash(null);
  200. gen.useLineCap(0);
  201. if (horz) {
  202. gen.useLineWidth(h);
  203. float ym = y1 + (h / 2);
  204. drawLine(gen, x1, ym, x2, ym);
  205. } else {
  206. gen.useLineWidth(w);
  207. float xm = x1 + (w / 2);
  208. drawLine(gen, xm, y1, xm, y2);
  209. }
  210. }
  211. }
  212. /** {@inheritDoc} */
  213. public void drawLine(Point start, Point end,
  214. int width, Color color, RuleStyle style) throws IOException {
  215. if (start.y != end.y) {
  216. //TODO Support arbitrary lines if necessary
  217. throw new UnsupportedOperationException(
  218. "Can only deal with horizontal lines right now");
  219. }
  220. saveGraphicsState();
  221. int half = width / 2;
  222. int starty = start.y - half;
  223. //Rectangle boundingRect = new Rectangle(start.x, start.y - half, end.x - start.x, width);
  224. switch (style.getEnumValue()) {
  225. case Constants.EN_SOLID:
  226. case Constants.EN_DASHED:
  227. case Constants.EN_DOUBLE:
  228. drawBorderLine(start.x, starty, end.x, starty + width,
  229. true, true, style.getEnumValue(), color);
  230. break;
  231. case Constants.EN_DOTTED:
  232. clipRect(start.x, starty, end.x - start.x, width);
  233. //This displaces the dots to the right by half a dot's width
  234. //TODO There's room for improvement here
  235. generator.concatMatrix(1, 0, 0, 1, toPoints(half), 0);
  236. drawBorderLine(start.x, starty, end.x, starty + width,
  237. true, true, style.getEnumValue(), color);
  238. break;
  239. case Constants.EN_GROOVE:
  240. case Constants.EN_RIDGE:
  241. generator.useColor(ColorUtil.lightenColor(color, 0.6f));
  242. moveTo(start.x, starty);
  243. lineTo(end.x, starty);
  244. lineTo(end.x, starty + 2 * half);
  245. lineTo(start.x, starty + 2 * half);
  246. closePath();
  247. generator.write(" " + generator.mapCommand("fill"));
  248. generator.writeln(" " + generator.mapCommand("newpath"));
  249. generator.useColor(color);
  250. if (style == RuleStyle.GROOVE) {
  251. moveTo(start.x, starty);
  252. lineTo(end.x, starty);
  253. lineTo(end.x, starty + half);
  254. lineTo(start.x + half, starty + half);
  255. lineTo(start.x, starty + 2 * half);
  256. } else {
  257. moveTo(end.x, starty);
  258. lineTo(end.x, starty + 2 * half);
  259. lineTo(start.x, starty + 2 * half);
  260. lineTo(start.x, starty + half);
  261. lineTo(end.x - half, starty + half);
  262. }
  263. closePath();
  264. generator.write(" " + generator.mapCommand("fill"));
  265. generator.writeln(" " + generator.mapCommand("newpath"));
  266. break;
  267. default:
  268. throw new UnsupportedOperationException("rule style not supported");
  269. }
  270. restoreGraphicsState();
  271. }
  272. private static float toPoints(int mpt) {
  273. return mpt / 1000f;
  274. }
  275. /** {@inheritDoc} */
  276. public void moveTo(int x, int y) throws IOException {
  277. generator.writeln(generator.formatDouble(toPoints(x)) + " "
  278. + generator.formatDouble(toPoints(y)) + " " + generator.mapCommand("moveto"));
  279. }
  280. /** {@inheritDoc} */
  281. public void lineTo(int x, int y) throws IOException {
  282. generator.writeln(generator.formatDouble(toPoints(x)) + " "
  283. + generator.formatDouble(toPoints(y)) + " " + generator.mapCommand("lineto"));
  284. }
  285. /** {@inheritDoc} */
  286. public void arcTo(final double startAngle, final double endAngle, final int cx, final int cy,
  287. final int width, final int height) throws IOException {
  288. arcToBezierCurveTransformer.arcTo(startAngle, endAngle, cx, cy, width, height);
  289. }
  290. /** {@inheritDoc} */
  291. public void closePath() throws IOException {
  292. generator.writeln("cp");
  293. }
  294. private void clipRect(int x, int y, int width, int height) throws IOException {
  295. generator.defineRect(toPoints(x), toPoints(y), toPoints(width), toPoints(height));
  296. clip();
  297. }
  298. /** {@inheritDoc} */
  299. public void clip() throws IOException {
  300. generator.writeln(generator.mapCommand("clip") + " " + generator.mapCommand("newpath"));
  301. }
  302. /** {@inheritDoc} */
  303. public void saveGraphicsState() throws IOException {
  304. generator.saveGraphicsState();
  305. }
  306. /** {@inheritDoc} */
  307. public void restoreGraphicsState() throws IOException {
  308. generator.restoreGraphicsState();
  309. }
  310. /** {@inheritDoc} */
  311. public void rotateCoordinates(double angle) throws IOException {
  312. StringBuffer sb = new StringBuffer()
  313. .append(generator.formatDouble(angle * 180d / Math.PI))
  314. .append(" rotate ");
  315. generator.writeln(sb.toString());
  316. }
  317. /** {@inheritDoc} */
  318. public void translateCoordinates(int xTranslate, int yTranslate) throws IOException {
  319. StringBuffer sb = new StringBuffer()
  320. .append(generator.formatDouble(toPoints(xTranslate)))
  321. .append(" ")
  322. .append(generator.formatDouble(toPoints(yTranslate)))
  323. .append(" translate ");
  324. generator.writeln(sb.toString());
  325. }
  326. /** {@inheritDoc} */
  327. public void scaleCoordinates(float xScale, float yScale) throws IOException {
  328. StringBuffer sb = new StringBuffer()
  329. .append(generator.formatDouble(xScale))
  330. .append(" ")
  331. .append(generator.formatDouble(yScale))
  332. .append(" scale ");
  333. generator.writeln(sb.toString());
  334. }
  335. /** {@inheritDoc} */
  336. public void cubicBezierTo(int p1x, int p1y, int p2x, int p2y, int p3x, int p3y)
  337. throws IOException {
  338. StringBuffer sb = new StringBuffer()
  339. .append(generator.formatDouble(toPoints(p1x)))
  340. .append(" ")
  341. .append(generator.formatDouble(toPoints(p1y)))
  342. .append(" ")
  343. .append(generator.formatDouble(toPoints(p2x)))
  344. .append(" ")
  345. .append(generator.formatDouble(toPoints(p2y)))
  346. .append(" ")
  347. .append(generator.formatDouble(toPoints(p3x)))
  348. .append(" ")
  349. .append(generator.formatDouble(toPoints(p3y)))
  350. .append(" curveto ");
  351. generator.writeln(sb.toString());
  352. }
  353. }