Du kan inte välja fler än 25 ämnen Ämnen måste starta med en bokstav eller siffra, kan innehålla bindestreck ('-') och vara max 35 tecken långa.

Function.java 16KB

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