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.

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506
  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. package org.apache.fop.render.gradient;
  18. import java.util.ArrayList;
  19. import java.util.Arrays;
  20. import java.util.Collections;
  21. import java.util.List;
  22. import org.apache.fop.render.gradient.GradientMaker.DoubleFormatter;
  23. public class Function {
  24. public interface SubFunctionRenderer {
  25. void outputFunction(StringBuilder out, int functionIndex);
  26. }
  27. /**
  28. * Required: The Type of function (0,2,3,4) default is 0.
  29. */
  30. private int functionType;
  31. /**
  32. * Required: 2 * m Array of Double numbers which are possible inputs to the function
  33. */
  34. private List<Double> domain;
  35. /**
  36. * Required: 2 * n Array of Double numbers which are possible outputs to the function
  37. */
  38. private List<Double> range;
  39. /* ********************TYPE 0***************************** */
  40. // FunctionType 0 specific function guts
  41. /**
  42. * Required: Array containing the Integer size of the Domain and Range, respectively.
  43. * Note: This is really more like two seperate integers, sizeDomain, and sizeRange,
  44. * but since they're expressed as an array in PDF, my implementation reflects that.
  45. */
  46. protected List<Double> size;
  47. /**
  48. * Required for Type 0: Number of Bits used to represent each sample value.
  49. * Limited to 1,2,4,8,12,16,24, or 32
  50. */
  51. private int bitsPerSample = 1;
  52. /**
  53. * Optional for Type 0: order of interpolation between samples.
  54. * Limited to linear (1) or cubic (3). Default is 1
  55. */
  56. private int order = 1;
  57. /**
  58. * Optional for Type 0: A 2 * m array of Doubles which provides a
  59. * linear mapping of input values to the domain.
  60. *
  61. * Required for Type 3: A 2 * k array of Doubles that, taken
  62. * in pairs, map each subset of the domain defined by Domain
  63. * and the Bounds array to the domain of the corresponding function.
  64. * Should be two values per function, usually (0,1),
  65. * as in [0 1 0 1] for 2 functions.
  66. */
  67. private List<Double> encode;
  68. /**
  69. * Optional for Type 0: A 2 * n array of Doubles which provides
  70. * a linear mapping of sample values to the range. Defaults to Range.
  71. */
  72. private List<Double> decode;
  73. /**
  74. * Optional For Type 0: A stream of sample values
  75. */
  76. /**
  77. * Required For Type 4: Postscript Calculator function
  78. * composed of arithmetic, boolean, and stack operators + boolean constants
  79. */
  80. private StringBuffer functionDataStream;
  81. /**
  82. * Required (possibly) For Type 0: A vector of Strings for the
  83. * various filters to be used to decode the stream.
  84. * These are how the string is compressed. Flate, LZW, etc.
  85. */
  86. private List<String> filter;
  87. /* *************************TYPE 2************************** */
  88. /**
  89. * Required For Type 2: An Array of n Doubles defining
  90. * the function result when x=0. Default is [0].
  91. */
  92. private float[] cZero;
  93. /**
  94. * Required For Type 2: An Array of n Doubles defining
  95. * the function result when x=1. Default is [1].
  96. */
  97. private float[] cOne;
  98. /**
  99. * Required for Type 2: The interpolation exponent.
  100. * Each value x will return n results.
  101. * Must be greater than 0.
  102. */
  103. private double interpolationExponentN = 1;
  104. /* *************************TYPE 3************************** */
  105. /**
  106. * Required for Type 3: An vector of PDFFunctions which
  107. * form an array of k single input functions making up
  108. * the stitching function.
  109. */
  110. private List<Function> functions;
  111. /**
  112. * Optional for Type 3: An array of (k-1) Doubles that,
  113. * in combination with Domain, define the intervals to which
  114. * each function from the Functions array apply. Bounds
  115. * elements must be in order of increasing magnitude,
  116. * and each value must be within the value of Domain.
  117. * k is the number of functions.
  118. * If you pass null, it will output (1/k) in an array of k-1 elements.
  119. * This makes each function responsible for an equal amount of the stitching function.
  120. * It makes the gradient even.
  121. */
  122. private List<Float> bounds;
  123. /**
  124. * create an complete Function object of Type 2, an Exponential Interpolation function.
  125. *
  126. * Use null for an optional object parameter if you choose not to use it.
  127. * For optional int parameters, pass the default.
  128. * @param domain List objects of Double objects.
  129. * This is the domain of the function.
  130. * See page 264 of the PDF 1.3 Spec.
  131. * @param range List of Doubles that is the Range of the function.
  132. * See page 264 of the PDF 1.3 Spec.
  133. * @param cZero This is a vector of Double objects which defines the function result
  134. * when x=0.
  135. *
  136. * This attribute is optional.
  137. * It's described on page 268 of the PDF 1.3 spec.
  138. * @param cOne This is a vector of Double objects which defines the function result
  139. * when x=1.
  140. *
  141. * This attribute is optional.
  142. * It's described on page 268 of the PDF 1.3 spec.
  143. * @param interpolationExponentN This is the inerpolation exponent.
  144. *
  145. * This attribute is required.
  146. * PDF Spec page 268
  147. */
  148. public Function(List<Double> domain, List<Double> range, float[] cZero, float[] cOne,
  149. double interpolationExponentN) {
  150. this(2, domain, range);
  151. this.cZero = cZero;
  152. this.cOne = cOne;
  153. this.interpolationExponentN = interpolationExponentN;
  154. }
  155. /**
  156. * create an complete Function object of Type 3, a Stitching function.
  157. *
  158. * Use null for an optional object parameter if you choose not to use it.
  159. * For optional int parameters, pass the default.
  160. * @param domain List objects of Double objects.
  161. * This is the domain of the function.
  162. * See page 264 of the PDF 1.3 Spec.
  163. * @param range List objects of Double objects.
  164. * This is the Range of the function.
  165. * See page 264 of the PDF 1.3 Spec.
  166. * @param functions A List of the PDFFunction objects that the stitching function stitches.
  167. *
  168. * This attributed is required.
  169. * It is described on page 269 of the PDF spec.
  170. * @param bounds This is a vector of Doubles representing the numbers that,
  171. * in conjunction with Domain define the intervals to which each function from
  172. * the 'functions' object applies. It must be in order of increasing magnitude,
  173. * and each must be within Domain.
  174. *
  175. * It basically sets how much of the gradient each function handles.
  176. *
  177. * This attributed is required.
  178. * It's described on page 269 of the PDF 1.3 spec.
  179. * @param encode List objects of Double objects.
  180. * This is the linear mapping of input values intop the domain
  181. * of the function's sample table. Default is hard to represent in
  182. * ascii, but basically [0 (Size0 1) 0 (Size1 1)...].
  183. * This attribute is required.
  184. *
  185. * See page 270 in the PDF 1.3 spec.
  186. */
  187. public Function(List<Double> domain, List<Double> range, List<Function> functions,
  188. List<Float> bounds, List<Double> encode) {
  189. this(3, domain, range);
  190. this.functions = functions;
  191. this.bounds = bounds;
  192. this.encode = makeEncode(encode);
  193. }
  194. private List<Double> makeEncode(List<Double> encode) {
  195. if (encode != null) {
  196. return encode;
  197. } else {
  198. encode = new ArrayList<Double>(functions.size() * 2);
  199. for (int i = 0; i < functions.size(); i++) {
  200. encode.add(0.0);
  201. encode.add(1.0);
  202. }
  203. return encode;
  204. }
  205. }
  206. private Function(int functionType, List<Double> domain, List<Double> range) {
  207. this.functionType = functionType;
  208. this.domain = (domain == null) ? Arrays.asList(0.0, 1.0) : domain;
  209. this.range = range;
  210. }
  211. /**
  212. * Gets the function type
  213. */
  214. public int getFunctionType() {
  215. return functionType;
  216. }
  217. /**
  218. * Gets the function bounds
  219. */
  220. public List<Float> getBounds() {
  221. return bounds;
  222. }
  223. /**
  224. * The function domain
  225. */
  226. public List<Double> getDomain() {
  227. return domain;
  228. }
  229. /**
  230. * The function size
  231. */
  232. public List<Double> getSize() {
  233. return size;
  234. }
  235. /**
  236. * Gets the function encoding
  237. */
  238. public List<Double> getEncode() {
  239. return encode;
  240. }
  241. /**
  242. * Gets the sub-functions
  243. */
  244. public List<Function> getFunctions() {
  245. if (functions == null) {
  246. return Collections.emptyList();
  247. } else {
  248. return functions;
  249. }
  250. }
  251. /**
  252. * Gets the function filter
  253. */
  254. public List<String> getFilter() {
  255. return filter;
  256. }
  257. /**
  258. * Gets the bits per sample of the function
  259. */
  260. public int getBitsPerSample() {
  261. return bitsPerSample;
  262. }
  263. /**
  264. * Gets the interpolation exponent of the function
  265. */
  266. public double getInterpolationExponentN() {
  267. return interpolationExponentN;
  268. }
  269. /**
  270. * Gets the function order
  271. */
  272. public int getOrder() {
  273. return order;
  274. }
  275. /**
  276. * Gets the function range
  277. */
  278. public List<Double> getRange() {
  279. return range;
  280. }
  281. /**
  282. * Gets the function decoding
  283. */
  284. public List<Double> getDecode() {
  285. return decode;
  286. }
  287. /**
  288. * Gets the function data stream
  289. */
  290. public StringBuffer getDataStream() {
  291. return functionDataStream;
  292. }
  293. /**
  294. * Gets the function C0 value (color for gradient)
  295. */
  296. public float[] getCZero() {
  297. return cZero;
  298. }
  299. /**
  300. * Gets the function C1 value (color for gradient)
  301. */
  302. public float[] getCOne() {
  303. return cOne;
  304. }
  305. public String output(StringBuilder out, DoubleFormatter doubleFormatter,
  306. SubFunctionRenderer subFunctionRenderer) {
  307. out.append("<<\n/FunctionType " + functionType + "\n");
  308. outputDomain(out, doubleFormatter);
  309. if (this.functionType == 0) {
  310. outputSize(out, doubleFormatter);
  311. outputEncode(out, doubleFormatter);
  312. outputBitsPerSample(out);
  313. outputOrder(out);
  314. outputRange(out, doubleFormatter);
  315. outputDecode(out, doubleFormatter);
  316. if (functionDataStream != null) {
  317. out.append("/Length " + (functionDataStream.length() + 1) + "\n");
  318. }
  319. outputFilter(out);
  320. out.append(">>");
  321. if (functionDataStream != null) {
  322. out.append("\nstream\n" + functionDataStream + "\nendstream");
  323. }
  324. } else if (functionType == 2) {
  325. outputRange(out, doubleFormatter);
  326. outputCZero(out, doubleFormatter);
  327. outputCOne(out, doubleFormatter);
  328. outputInterpolationExponentN(out, doubleFormatter);
  329. out.append(">>");
  330. } else if (functionType == 3) {
  331. outputRange(out, doubleFormatter);
  332. if (!functions.isEmpty()) {
  333. out.append("/Functions [ ");
  334. for (int i = 0; i < functions.size(); i++) {
  335. subFunctionRenderer.outputFunction(out, i);
  336. out.append(' ');
  337. }
  338. out.append("]\n");
  339. }
  340. outputEncode(out, doubleFormatter);
  341. out.append("/Bounds ");
  342. if (bounds != null) {
  343. GradientMaker.outputDoubles(out, doubleFormatter, bounds);
  344. } else if (!functions.isEmpty()) {
  345. // if there are n functions,
  346. // there must be n-1 bounds.
  347. // so let each function handle an equal portion
  348. // of the whole. e.g. if there are 4, then [ 0.25 0.25 0.25 ]
  349. int numberOfFunctions = functions.size();
  350. String functionsFraction = doubleFormatter.formatDouble(1.0 / numberOfFunctions);
  351. out.append("[ ");
  352. for (int i = 0; i + 1 < numberOfFunctions; i++) {
  353. out.append(functionsFraction);
  354. out.append(" ");
  355. }
  356. out.append("]");
  357. }
  358. out.append("\n>>");
  359. } else if (functionType == 4) {
  360. outputRange(out, doubleFormatter);
  361. if (functionDataStream != null) {
  362. out.append("/Length " + (functionDataStream.length() + 1) + "\n");
  363. }
  364. out.append(">>");
  365. if (functionDataStream != null) {
  366. out.append("\nstream\n{ " + functionDataStream + " }\nendstream");
  367. }
  368. }
  369. return out.toString();
  370. }
  371. private void outputDomain(StringBuilder p, DoubleFormatter doubleFormatter) {
  372. p.append("/Domain ");
  373. GradientMaker.outputDoubles(p, doubleFormatter, domain);
  374. p.append("\n");
  375. }
  376. private void outputSize(StringBuilder out, DoubleFormatter doubleFormatter) {
  377. if (size != null) {
  378. out.append("/Size ");
  379. GradientMaker.outputDoubles(out, doubleFormatter, size);
  380. out.append("\n");
  381. }
  382. }
  383. private void outputBitsPerSample(StringBuilder out) {
  384. out.append("/BitsPerSample " + bitsPerSample + "\n");
  385. }
  386. private void outputOrder(StringBuilder out) {
  387. if (order == 1 || order == 3) {
  388. out.append("\n/Order " + order + "\n");
  389. }
  390. }
  391. private void outputRange(StringBuilder out, DoubleFormatter doubleFormatter) {
  392. if (range != null) {
  393. out.append("/Range ");
  394. GradientMaker.outputDoubles(out, doubleFormatter, range);
  395. out.append("\n");
  396. }
  397. }
  398. private void outputEncode(StringBuilder out, DoubleFormatter doubleFormatter) {
  399. out.append("/Encode ");
  400. GradientMaker.outputDoubles(out, doubleFormatter, encode);
  401. out.append("\n");
  402. }
  403. private void outputDecode(StringBuilder out, DoubleFormatter doubleFormatter) {
  404. if (decode != null) {
  405. out.append("/Decode ");
  406. GradientMaker.outputDoubles(out, doubleFormatter, decode);
  407. out.append("\n");
  408. }
  409. }
  410. private void outputFilter(StringBuilder out) {
  411. if (filter != null) {
  412. int size = filter.size();
  413. out.append("/Filter ");
  414. if (size == 1) {
  415. out.append("/" + filter.get(0) + "\n");
  416. } else {
  417. out.append("[ ");
  418. for (int i = 0; i < size; i++) {
  419. out.append("/" + filter.get(0) + " ");
  420. }
  421. out.append("]\n");
  422. }
  423. }
  424. }
  425. private void outputCZero(StringBuilder out, DoubleFormatter doubleFormatter) {
  426. if (cZero != null) {
  427. out.append("/C0 [ ");
  428. for (float c : cZero) {
  429. out.append(doubleFormatter.formatDouble(c));
  430. out.append(" ");
  431. }
  432. out.append("]\n");
  433. }
  434. }
  435. private void outputCOne(StringBuilder out, DoubleFormatter doubleFormatter) {
  436. if (cOne != null) {
  437. out.append("/C1 [ ");
  438. for (float c : cOne) {
  439. out.append(doubleFormatter.formatDouble(c));
  440. out.append(" ");
  441. }
  442. out.append("]\n");
  443. }
  444. }
  445. private void outputInterpolationExponentN(StringBuilder out, DoubleFormatter doubleFormatter) {
  446. out.append("/N ");
  447. out.append(doubleFormatter.formatDouble(interpolationExponentN));
  448. out.append("\n");
  449. }
  450. }