pattern.js 26 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788
  1. /* Copyright 2017 Mozilla Foundation
  2. *
  3. * Licensed under the Apache License, Version 2.0 (the "License");
  4. * you may not use this file except in compliance with the License.
  5. * You may obtain a copy of the License at
  6. *
  7. * http://www.apache.org/licenses/LICENSE-2.0
  8. *
  9. * Unless required by applicable law or agreed to in writing, software
  10. * distributed under the License is distributed on an "AS IS" BASIS,
  11. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  12. * See the License for the specific language governing permissions and
  13. * limitations under the License.
  14. */
  15. 'use strict';
  16. var sharedUtil = require('../shared/util.js');
  17. var corePrimitives = require('./primitives.js');
  18. var coreFunction = require('./function.js');
  19. var coreColorSpace = require('./colorspace.js');
  20. var UNSUPPORTED_FEATURES = sharedUtil.UNSUPPORTED_FEATURES;
  21. var MissingDataException = sharedUtil.MissingDataException;
  22. var Util = sharedUtil.Util;
  23. var assert = sharedUtil.assert;
  24. var error = sharedUtil.error;
  25. var info = sharedUtil.info;
  26. var warn = sharedUtil.warn;
  27. var isStream = corePrimitives.isStream;
  28. var PDFFunction = coreFunction.PDFFunction;
  29. var ColorSpace = coreColorSpace.ColorSpace;
  30. var ShadingType = {
  31. FUNCTION_BASED: 1,
  32. AXIAL: 2,
  33. RADIAL: 3,
  34. FREE_FORM_MESH: 4,
  35. LATTICE_FORM_MESH: 5,
  36. COONS_PATCH_MESH: 6,
  37. TENSOR_PATCH_MESH: 7
  38. };
  39. var Pattern = function PatternClosure() {
  40. function Pattern() {
  41. error('should not call Pattern constructor');
  42. }
  43. Pattern.prototype = {
  44. getPattern: function Pattern_getPattern(ctx) {
  45. error('Should not call Pattern.getStyle: ' + ctx);
  46. }
  47. };
  48. Pattern.parseShading = function Pattern_parseShading(shading, matrix, xref, res, handler) {
  49. var dict = isStream(shading) ? shading.dict : shading;
  50. var type = dict.get('ShadingType');
  51. try {
  52. switch (type) {
  53. case ShadingType.AXIAL:
  54. case ShadingType.RADIAL:
  55. return new Shadings.RadialAxial(dict, matrix, xref, res);
  56. case ShadingType.FREE_FORM_MESH:
  57. case ShadingType.LATTICE_FORM_MESH:
  58. case ShadingType.COONS_PATCH_MESH:
  59. case ShadingType.TENSOR_PATCH_MESH:
  60. return new Shadings.Mesh(shading, matrix, xref, res);
  61. default:
  62. throw new Error('Unsupported ShadingType: ' + type);
  63. }
  64. } catch (ex) {
  65. if (ex instanceof MissingDataException) {
  66. throw ex;
  67. }
  68. handler.send('UnsupportedFeature', { featureId: UNSUPPORTED_FEATURES.shadingPattern });
  69. warn(ex);
  70. return new Shadings.Dummy();
  71. }
  72. };
  73. return Pattern;
  74. }();
  75. var Shadings = {};
  76. Shadings.SMALL_NUMBER = 1e-6;
  77. Shadings.RadialAxial = function RadialAxialClosure() {
  78. function RadialAxial(dict, matrix, xref, res) {
  79. this.matrix = matrix;
  80. this.coordsArr = dict.getArray('Coords');
  81. this.shadingType = dict.get('ShadingType');
  82. this.type = 'Pattern';
  83. var cs = dict.get('ColorSpace', 'CS');
  84. cs = ColorSpace.parse(cs, xref, res);
  85. this.cs = cs;
  86. var t0 = 0.0,
  87. t1 = 1.0;
  88. if (dict.has('Domain')) {
  89. var domainArr = dict.getArray('Domain');
  90. t0 = domainArr[0];
  91. t1 = domainArr[1];
  92. }
  93. var extendStart = false,
  94. extendEnd = false;
  95. if (dict.has('Extend')) {
  96. var extendArr = dict.getArray('Extend');
  97. extendStart = extendArr[0];
  98. extendEnd = extendArr[1];
  99. }
  100. if (this.shadingType === ShadingType.RADIAL && (!extendStart || !extendEnd)) {
  101. var x1 = this.coordsArr[0];
  102. var y1 = this.coordsArr[1];
  103. var r1 = this.coordsArr[2];
  104. var x2 = this.coordsArr[3];
  105. var y2 = this.coordsArr[4];
  106. var r2 = this.coordsArr[5];
  107. var distance = Math.sqrt((x1 - x2) * (x1 - x2) + (y1 - y2) * (y1 - y2));
  108. if (r1 <= r2 + distance && r2 <= r1 + distance) {
  109. warn('Unsupported radial gradient.');
  110. }
  111. }
  112. this.extendStart = extendStart;
  113. this.extendEnd = extendEnd;
  114. var fnObj = dict.get('Function');
  115. var fn = PDFFunction.parseArray(xref, fnObj);
  116. var diff = t1 - t0;
  117. var step = diff / 10;
  118. var colorStops = this.colorStops = [];
  119. if (t0 >= t1 || step <= 0) {
  120. info('Bad shading domain.');
  121. return;
  122. }
  123. var color = new Float32Array(cs.numComps),
  124. ratio = new Float32Array(1);
  125. var rgbColor;
  126. for (var i = t0; i <= t1; i += step) {
  127. ratio[0] = i;
  128. fn(ratio, 0, color, 0);
  129. rgbColor = cs.getRgb(color, 0);
  130. var cssColor = Util.makeCssRgb(rgbColor[0], rgbColor[1], rgbColor[2]);
  131. colorStops.push([(i - t0) / diff, cssColor]);
  132. }
  133. var background = 'transparent';
  134. if (dict.has('Background')) {
  135. rgbColor = cs.getRgb(dict.get('Background'), 0);
  136. background = Util.makeCssRgb(rgbColor[0], rgbColor[1], rgbColor[2]);
  137. }
  138. if (!extendStart) {
  139. colorStops.unshift([0, background]);
  140. colorStops[1][0] += Shadings.SMALL_NUMBER;
  141. }
  142. if (!extendEnd) {
  143. colorStops[colorStops.length - 1][0] -= Shadings.SMALL_NUMBER;
  144. colorStops.push([1, background]);
  145. }
  146. this.colorStops = colorStops;
  147. }
  148. RadialAxial.prototype = {
  149. getIR: function RadialAxial_getIR() {
  150. var coordsArr = this.coordsArr;
  151. var shadingType = this.shadingType;
  152. var type, p0, p1, r0, r1;
  153. if (shadingType === ShadingType.AXIAL) {
  154. p0 = [coordsArr[0], coordsArr[1]];
  155. p1 = [coordsArr[2], coordsArr[3]];
  156. r0 = null;
  157. r1 = null;
  158. type = 'axial';
  159. } else if (shadingType === ShadingType.RADIAL) {
  160. p0 = [coordsArr[0], coordsArr[1]];
  161. p1 = [coordsArr[3], coordsArr[4]];
  162. r0 = coordsArr[2];
  163. r1 = coordsArr[5];
  164. type = 'radial';
  165. } else {
  166. error('getPattern type unknown: ' + shadingType);
  167. }
  168. var matrix = this.matrix;
  169. if (matrix) {
  170. p0 = Util.applyTransform(p0, matrix);
  171. p1 = Util.applyTransform(p1, matrix);
  172. if (shadingType === ShadingType.RADIAL) {
  173. var scale = Util.singularValueDecompose2dScale(matrix);
  174. r0 *= scale[0];
  175. r1 *= scale[1];
  176. }
  177. }
  178. return ['RadialAxial', type, this.colorStops, p0, p1, r0, r1];
  179. }
  180. };
  181. return RadialAxial;
  182. }();
  183. Shadings.Mesh = function MeshClosure() {
  184. function MeshStreamReader(stream, context) {
  185. this.stream = stream;
  186. this.context = context;
  187. this.buffer = 0;
  188. this.bufferLength = 0;
  189. var numComps = context.numComps;
  190. this.tmpCompsBuf = new Float32Array(numComps);
  191. var csNumComps = context.colorSpace.numComps;
  192. this.tmpCsCompsBuf = context.colorFn ? new Float32Array(csNumComps) : this.tmpCompsBuf;
  193. }
  194. MeshStreamReader.prototype = {
  195. get hasData() {
  196. if (this.stream.end) {
  197. return this.stream.pos < this.stream.end;
  198. }
  199. if (this.bufferLength > 0) {
  200. return true;
  201. }
  202. var nextByte = this.stream.getByte();
  203. if (nextByte < 0) {
  204. return false;
  205. }
  206. this.buffer = nextByte;
  207. this.bufferLength = 8;
  208. return true;
  209. },
  210. readBits: function MeshStreamReader_readBits(n) {
  211. var buffer = this.buffer;
  212. var bufferLength = this.bufferLength;
  213. if (n === 32) {
  214. if (bufferLength === 0) {
  215. return (this.stream.getByte() << 24 | this.stream.getByte() << 16 | this.stream.getByte() << 8 | this.stream.getByte()) >>> 0;
  216. }
  217. buffer = buffer << 24 | this.stream.getByte() << 16 | this.stream.getByte() << 8 | this.stream.getByte();
  218. var nextByte = this.stream.getByte();
  219. this.buffer = nextByte & (1 << bufferLength) - 1;
  220. return (buffer << 8 - bufferLength | (nextByte & 0xFF) >> bufferLength) >>> 0;
  221. }
  222. if (n === 8 && bufferLength === 0) {
  223. return this.stream.getByte();
  224. }
  225. while (bufferLength < n) {
  226. buffer = buffer << 8 | this.stream.getByte();
  227. bufferLength += 8;
  228. }
  229. bufferLength -= n;
  230. this.bufferLength = bufferLength;
  231. this.buffer = buffer & (1 << bufferLength) - 1;
  232. return buffer >> bufferLength;
  233. },
  234. align: function MeshStreamReader_align() {
  235. this.buffer = 0;
  236. this.bufferLength = 0;
  237. },
  238. readFlag: function MeshStreamReader_readFlag() {
  239. return this.readBits(this.context.bitsPerFlag);
  240. },
  241. readCoordinate: function MeshStreamReader_readCoordinate() {
  242. var bitsPerCoordinate = this.context.bitsPerCoordinate;
  243. var xi = this.readBits(bitsPerCoordinate);
  244. var yi = this.readBits(bitsPerCoordinate);
  245. var decode = this.context.decode;
  246. var scale = bitsPerCoordinate < 32 ? 1 / ((1 << bitsPerCoordinate) - 1) : 2.3283064365386963e-10;
  247. return [xi * scale * (decode[1] - decode[0]) + decode[0], yi * scale * (decode[3] - decode[2]) + decode[2]];
  248. },
  249. readComponents: function MeshStreamReader_readComponents() {
  250. var numComps = this.context.numComps;
  251. var bitsPerComponent = this.context.bitsPerComponent;
  252. var scale = bitsPerComponent < 32 ? 1 / ((1 << bitsPerComponent) - 1) : 2.3283064365386963e-10;
  253. var decode = this.context.decode;
  254. var components = this.tmpCompsBuf;
  255. for (var i = 0, j = 4; i < numComps; i++, j += 2) {
  256. var ci = this.readBits(bitsPerComponent);
  257. components[i] = ci * scale * (decode[j + 1] - decode[j]) + decode[j];
  258. }
  259. var color = this.tmpCsCompsBuf;
  260. if (this.context.colorFn) {
  261. this.context.colorFn(components, 0, color, 0);
  262. }
  263. return this.context.colorSpace.getRgb(color, 0);
  264. }
  265. };
  266. function decodeType4Shading(mesh, reader) {
  267. var coords = mesh.coords;
  268. var colors = mesh.colors;
  269. var operators = [];
  270. var ps = [];
  271. var verticesLeft = 0;
  272. while (reader.hasData) {
  273. var f = reader.readFlag();
  274. var coord = reader.readCoordinate();
  275. var color = reader.readComponents();
  276. if (verticesLeft === 0) {
  277. assert(0 <= f && f <= 2, 'Unknown type4 flag');
  278. switch (f) {
  279. case 0:
  280. verticesLeft = 3;
  281. break;
  282. case 1:
  283. ps.push(ps[ps.length - 2], ps[ps.length - 1]);
  284. verticesLeft = 1;
  285. break;
  286. case 2:
  287. ps.push(ps[ps.length - 3], ps[ps.length - 1]);
  288. verticesLeft = 1;
  289. break;
  290. }
  291. operators.push(f);
  292. }
  293. ps.push(coords.length);
  294. coords.push(coord);
  295. colors.push(color);
  296. verticesLeft--;
  297. reader.align();
  298. }
  299. mesh.figures.push({
  300. type: 'triangles',
  301. coords: new Int32Array(ps),
  302. colors: new Int32Array(ps)
  303. });
  304. }
  305. function decodeType5Shading(mesh, reader, verticesPerRow) {
  306. var coords = mesh.coords;
  307. var colors = mesh.colors;
  308. var ps = [];
  309. while (reader.hasData) {
  310. var coord = reader.readCoordinate();
  311. var color = reader.readComponents();
  312. ps.push(coords.length);
  313. coords.push(coord);
  314. colors.push(color);
  315. }
  316. mesh.figures.push({
  317. type: 'lattice',
  318. coords: new Int32Array(ps),
  319. colors: new Int32Array(ps),
  320. verticesPerRow: verticesPerRow
  321. });
  322. }
  323. var MIN_SPLIT_PATCH_CHUNKS_AMOUNT = 3;
  324. var MAX_SPLIT_PATCH_CHUNKS_AMOUNT = 20;
  325. var TRIANGLE_DENSITY = 20;
  326. var getB = function getBClosure() {
  327. function buildB(count) {
  328. var lut = [];
  329. for (var i = 0; i <= count; i++) {
  330. var t = i / count,
  331. t_ = 1 - t;
  332. lut.push(new Float32Array([t_ * t_ * t_, 3 * t * t_ * t_, 3 * t * t * t_, t * t * t]));
  333. }
  334. return lut;
  335. }
  336. var cache = [];
  337. return function getB(count) {
  338. if (!cache[count]) {
  339. cache[count] = buildB(count);
  340. }
  341. return cache[count];
  342. };
  343. }();
  344. function buildFigureFromPatch(mesh, index) {
  345. var figure = mesh.figures[index];
  346. assert(figure.type === 'patch', 'Unexpected patch mesh figure');
  347. var coords = mesh.coords,
  348. colors = mesh.colors;
  349. var pi = figure.coords;
  350. var ci = figure.colors;
  351. var figureMinX = Math.min(coords[pi[0]][0], coords[pi[3]][0], coords[pi[12]][0], coords[pi[15]][0]);
  352. var figureMinY = Math.min(coords[pi[0]][1], coords[pi[3]][1], coords[pi[12]][1], coords[pi[15]][1]);
  353. var figureMaxX = Math.max(coords[pi[0]][0], coords[pi[3]][0], coords[pi[12]][0], coords[pi[15]][0]);
  354. var figureMaxY = Math.max(coords[pi[0]][1], coords[pi[3]][1], coords[pi[12]][1], coords[pi[15]][1]);
  355. var splitXBy = Math.ceil((figureMaxX - figureMinX) * TRIANGLE_DENSITY / (mesh.bounds[2] - mesh.bounds[0]));
  356. splitXBy = Math.max(MIN_SPLIT_PATCH_CHUNKS_AMOUNT, Math.min(MAX_SPLIT_PATCH_CHUNKS_AMOUNT, splitXBy));
  357. var splitYBy = Math.ceil((figureMaxY - figureMinY) * TRIANGLE_DENSITY / (mesh.bounds[3] - mesh.bounds[1]));
  358. splitYBy = Math.max(MIN_SPLIT_PATCH_CHUNKS_AMOUNT, Math.min(MAX_SPLIT_PATCH_CHUNKS_AMOUNT, splitYBy));
  359. var verticesPerRow = splitXBy + 1;
  360. var figureCoords = new Int32Array((splitYBy + 1) * verticesPerRow);
  361. var figureColors = new Int32Array((splitYBy + 1) * verticesPerRow);
  362. var k = 0;
  363. var cl = new Uint8Array(3),
  364. cr = new Uint8Array(3);
  365. var c0 = colors[ci[0]],
  366. c1 = colors[ci[1]],
  367. c2 = colors[ci[2]],
  368. c3 = colors[ci[3]];
  369. var bRow = getB(splitYBy),
  370. bCol = getB(splitXBy);
  371. for (var row = 0; row <= splitYBy; row++) {
  372. cl[0] = (c0[0] * (splitYBy - row) + c2[0] * row) / splitYBy | 0;
  373. cl[1] = (c0[1] * (splitYBy - row) + c2[1] * row) / splitYBy | 0;
  374. cl[2] = (c0[2] * (splitYBy - row) + c2[2] * row) / splitYBy | 0;
  375. cr[0] = (c1[0] * (splitYBy - row) + c3[0] * row) / splitYBy | 0;
  376. cr[1] = (c1[1] * (splitYBy - row) + c3[1] * row) / splitYBy | 0;
  377. cr[2] = (c1[2] * (splitYBy - row) + c3[2] * row) / splitYBy | 0;
  378. for (var col = 0; col <= splitXBy; col++, k++) {
  379. if ((row === 0 || row === splitYBy) && (col === 0 || col === splitXBy)) {
  380. continue;
  381. }
  382. var x = 0,
  383. y = 0;
  384. var q = 0;
  385. for (var i = 0; i <= 3; i++) {
  386. for (var j = 0; j <= 3; j++, q++) {
  387. var m = bRow[row][i] * bCol[col][j];
  388. x += coords[pi[q]][0] * m;
  389. y += coords[pi[q]][1] * m;
  390. }
  391. }
  392. figureCoords[k] = coords.length;
  393. coords.push([x, y]);
  394. figureColors[k] = colors.length;
  395. var newColor = new Uint8Array(3);
  396. newColor[0] = (cl[0] * (splitXBy - col) + cr[0] * col) / splitXBy | 0;
  397. newColor[1] = (cl[1] * (splitXBy - col) + cr[1] * col) / splitXBy | 0;
  398. newColor[2] = (cl[2] * (splitXBy - col) + cr[2] * col) / splitXBy | 0;
  399. colors.push(newColor);
  400. }
  401. }
  402. figureCoords[0] = pi[0];
  403. figureColors[0] = ci[0];
  404. figureCoords[splitXBy] = pi[3];
  405. figureColors[splitXBy] = ci[1];
  406. figureCoords[verticesPerRow * splitYBy] = pi[12];
  407. figureColors[verticesPerRow * splitYBy] = ci[2];
  408. figureCoords[verticesPerRow * splitYBy + splitXBy] = pi[15];
  409. figureColors[verticesPerRow * splitYBy + splitXBy] = ci[3];
  410. mesh.figures[index] = {
  411. type: 'lattice',
  412. coords: figureCoords,
  413. colors: figureColors,
  414. verticesPerRow: verticesPerRow
  415. };
  416. }
  417. function decodeType6Shading(mesh, reader) {
  418. var coords = mesh.coords;
  419. var colors = mesh.colors;
  420. var ps = new Int32Array(16);
  421. var cs = new Int32Array(4);
  422. while (reader.hasData) {
  423. var f = reader.readFlag();
  424. assert(0 <= f && f <= 3, 'Unknown type6 flag');
  425. var i, ii;
  426. var pi = coords.length;
  427. for (i = 0, ii = f !== 0 ? 8 : 12; i < ii; i++) {
  428. coords.push(reader.readCoordinate());
  429. }
  430. var ci = colors.length;
  431. for (i = 0, ii = f !== 0 ? 2 : 4; i < ii; i++) {
  432. colors.push(reader.readComponents());
  433. }
  434. var tmp1, tmp2, tmp3, tmp4;
  435. switch (f) {
  436. case 0:
  437. ps[12] = pi + 3;
  438. ps[13] = pi + 4;
  439. ps[14] = pi + 5;
  440. ps[15] = pi + 6;
  441. ps[8] = pi + 2;
  442. ps[11] = pi + 7;
  443. ps[4] = pi + 1;
  444. ps[7] = pi + 8;
  445. ps[0] = pi;
  446. ps[1] = pi + 11;
  447. ps[2] = pi + 10;
  448. ps[3] = pi + 9;
  449. cs[2] = ci + 1;
  450. cs[3] = ci + 2;
  451. cs[0] = ci;
  452. cs[1] = ci + 3;
  453. break;
  454. case 1:
  455. tmp1 = ps[12];
  456. tmp2 = ps[13];
  457. tmp3 = ps[14];
  458. tmp4 = ps[15];
  459. ps[12] = tmp4;
  460. ps[13] = pi + 0;
  461. ps[14] = pi + 1;
  462. ps[15] = pi + 2;
  463. ps[8] = tmp3;
  464. ps[11] = pi + 3;
  465. ps[4] = tmp2;
  466. ps[7] = pi + 4;
  467. ps[0] = tmp1;
  468. ps[1] = pi + 7;
  469. ps[2] = pi + 6;
  470. ps[3] = pi + 5;
  471. tmp1 = cs[2];
  472. tmp2 = cs[3];
  473. cs[2] = tmp2;
  474. cs[3] = ci;
  475. cs[0] = tmp1;
  476. cs[1] = ci + 1;
  477. break;
  478. case 2:
  479. tmp1 = ps[15];
  480. tmp2 = ps[11];
  481. ps[12] = ps[3];
  482. ps[13] = pi + 0;
  483. ps[14] = pi + 1;
  484. ps[15] = pi + 2;
  485. ps[8] = ps[7];
  486. ps[11] = pi + 3;
  487. ps[4] = tmp2;
  488. ps[7] = pi + 4;
  489. ps[0] = tmp1;
  490. ps[1] = pi + 7;
  491. ps[2] = pi + 6;
  492. ps[3] = pi + 5;
  493. tmp1 = cs[3];
  494. cs[2] = cs[1];
  495. cs[3] = ci;
  496. cs[0] = tmp1;
  497. cs[1] = ci + 1;
  498. break;
  499. case 3:
  500. ps[12] = ps[0];
  501. ps[13] = pi + 0;
  502. ps[14] = pi + 1;
  503. ps[15] = pi + 2;
  504. ps[8] = ps[1];
  505. ps[11] = pi + 3;
  506. ps[4] = ps[2];
  507. ps[7] = pi + 4;
  508. ps[0] = ps[3];
  509. ps[1] = pi + 7;
  510. ps[2] = pi + 6;
  511. ps[3] = pi + 5;
  512. cs[2] = cs[0];
  513. cs[3] = ci;
  514. cs[0] = cs[1];
  515. cs[1] = ci + 1;
  516. break;
  517. }
  518. ps[5] = coords.length;
  519. coords.push([(-4 * coords[ps[0]][0] - coords[ps[15]][0] + 6 * (coords[ps[4]][0] + coords[ps[1]][0]) - 2 * (coords[ps[12]][0] + coords[ps[3]][0]) + 3 * (coords[ps[13]][0] + coords[ps[7]][0])) / 9, (-4 * coords[ps[0]][1] - coords[ps[15]][1] + 6 * (coords[ps[4]][1] + coords[ps[1]][1]) - 2 * (coords[ps[12]][1] + coords[ps[3]][1]) + 3 * (coords[ps[13]][1] + coords[ps[7]][1])) / 9]);
  520. ps[6] = coords.length;
  521. coords.push([(-4 * coords[ps[3]][0] - coords[ps[12]][0] + 6 * (coords[ps[2]][0] + coords[ps[7]][0]) - 2 * (coords[ps[0]][0] + coords[ps[15]][0]) + 3 * (coords[ps[4]][0] + coords[ps[14]][0])) / 9, (-4 * coords[ps[3]][1] - coords[ps[12]][1] + 6 * (coords[ps[2]][1] + coords[ps[7]][1]) - 2 * (coords[ps[0]][1] + coords[ps[15]][1]) + 3 * (coords[ps[4]][1] + coords[ps[14]][1])) / 9]);
  522. ps[9] = coords.length;
  523. coords.push([(-4 * coords[ps[12]][0] - coords[ps[3]][0] + 6 * (coords[ps[8]][0] + coords[ps[13]][0]) - 2 * (coords[ps[0]][0] + coords[ps[15]][0]) + 3 * (coords[ps[11]][0] + coords[ps[1]][0])) / 9, (-4 * coords[ps[12]][1] - coords[ps[3]][1] + 6 * (coords[ps[8]][1] + coords[ps[13]][1]) - 2 * (coords[ps[0]][1] + coords[ps[15]][1]) + 3 * (coords[ps[11]][1] + coords[ps[1]][1])) / 9]);
  524. ps[10] = coords.length;
  525. coords.push([(-4 * coords[ps[15]][0] - coords[ps[0]][0] + 6 * (coords[ps[11]][0] + coords[ps[14]][0]) - 2 * (coords[ps[12]][0] + coords[ps[3]][0]) + 3 * (coords[ps[2]][0] + coords[ps[8]][0])) / 9, (-4 * coords[ps[15]][1] - coords[ps[0]][1] + 6 * (coords[ps[11]][1] + coords[ps[14]][1]) - 2 * (coords[ps[12]][1] + coords[ps[3]][1]) + 3 * (coords[ps[2]][1] + coords[ps[8]][1])) / 9]);
  526. mesh.figures.push({
  527. type: 'patch',
  528. coords: new Int32Array(ps),
  529. colors: new Int32Array(cs)
  530. });
  531. }
  532. }
  533. function decodeType7Shading(mesh, reader) {
  534. var coords = mesh.coords;
  535. var colors = mesh.colors;
  536. var ps = new Int32Array(16);
  537. var cs = new Int32Array(4);
  538. while (reader.hasData) {
  539. var f = reader.readFlag();
  540. assert(0 <= f && f <= 3, 'Unknown type7 flag');
  541. var i, ii;
  542. var pi = coords.length;
  543. for (i = 0, ii = f !== 0 ? 12 : 16; i < ii; i++) {
  544. coords.push(reader.readCoordinate());
  545. }
  546. var ci = colors.length;
  547. for (i = 0, ii = f !== 0 ? 2 : 4; i < ii; i++) {
  548. colors.push(reader.readComponents());
  549. }
  550. var tmp1, tmp2, tmp3, tmp4;
  551. switch (f) {
  552. case 0:
  553. ps[12] = pi + 3;
  554. ps[13] = pi + 4;
  555. ps[14] = pi + 5;
  556. ps[15] = pi + 6;
  557. ps[8] = pi + 2;
  558. ps[9] = pi + 13;
  559. ps[10] = pi + 14;
  560. ps[11] = pi + 7;
  561. ps[4] = pi + 1;
  562. ps[5] = pi + 12;
  563. ps[6] = pi + 15;
  564. ps[7] = pi + 8;
  565. ps[0] = pi;
  566. ps[1] = pi + 11;
  567. ps[2] = pi + 10;
  568. ps[3] = pi + 9;
  569. cs[2] = ci + 1;
  570. cs[3] = ci + 2;
  571. cs[0] = ci;
  572. cs[1] = ci + 3;
  573. break;
  574. case 1:
  575. tmp1 = ps[12];
  576. tmp2 = ps[13];
  577. tmp3 = ps[14];
  578. tmp4 = ps[15];
  579. ps[12] = tmp4;
  580. ps[13] = pi + 0;
  581. ps[14] = pi + 1;
  582. ps[15] = pi + 2;
  583. ps[8] = tmp3;
  584. ps[9] = pi + 9;
  585. ps[10] = pi + 10;
  586. ps[11] = pi + 3;
  587. ps[4] = tmp2;
  588. ps[5] = pi + 8;
  589. ps[6] = pi + 11;
  590. ps[7] = pi + 4;
  591. ps[0] = tmp1;
  592. ps[1] = pi + 7;
  593. ps[2] = pi + 6;
  594. ps[3] = pi + 5;
  595. tmp1 = cs[2];
  596. tmp2 = cs[3];
  597. cs[2] = tmp2;
  598. cs[3] = ci;
  599. cs[0] = tmp1;
  600. cs[1] = ci + 1;
  601. break;
  602. case 2:
  603. tmp1 = ps[15];
  604. tmp2 = ps[11];
  605. ps[12] = ps[3];
  606. ps[13] = pi + 0;
  607. ps[14] = pi + 1;
  608. ps[15] = pi + 2;
  609. ps[8] = ps[7];
  610. ps[9] = pi + 9;
  611. ps[10] = pi + 10;
  612. ps[11] = pi + 3;
  613. ps[4] = tmp2;
  614. ps[5] = pi + 8;
  615. ps[6] = pi + 11;
  616. ps[7] = pi + 4;
  617. ps[0] = tmp1;
  618. ps[1] = pi + 7;
  619. ps[2] = pi + 6;
  620. ps[3] = pi + 5;
  621. tmp1 = cs[3];
  622. cs[2] = cs[1];
  623. cs[3] = ci;
  624. cs[0] = tmp1;
  625. cs[1] = ci + 1;
  626. break;
  627. case 3:
  628. ps[12] = ps[0];
  629. ps[13] = pi + 0;
  630. ps[14] = pi + 1;
  631. ps[15] = pi + 2;
  632. ps[8] = ps[1];
  633. ps[9] = pi + 9;
  634. ps[10] = pi + 10;
  635. ps[11] = pi + 3;
  636. ps[4] = ps[2];
  637. ps[5] = pi + 8;
  638. ps[6] = pi + 11;
  639. ps[7] = pi + 4;
  640. ps[0] = ps[3];
  641. ps[1] = pi + 7;
  642. ps[2] = pi + 6;
  643. ps[3] = pi + 5;
  644. cs[2] = cs[0];
  645. cs[3] = ci;
  646. cs[0] = cs[1];
  647. cs[1] = ci + 1;
  648. break;
  649. }
  650. mesh.figures.push({
  651. type: 'patch',
  652. coords: new Int32Array(ps),
  653. colors: new Int32Array(cs)
  654. });
  655. }
  656. }
  657. function updateBounds(mesh) {
  658. var minX = mesh.coords[0][0],
  659. minY = mesh.coords[0][1],
  660. maxX = minX,
  661. maxY = minY;
  662. for (var i = 1, ii = mesh.coords.length; i < ii; i++) {
  663. var x = mesh.coords[i][0],
  664. y = mesh.coords[i][1];
  665. minX = minX > x ? x : minX;
  666. minY = minY > y ? y : minY;
  667. maxX = maxX < x ? x : maxX;
  668. maxY = maxY < y ? y : maxY;
  669. }
  670. mesh.bounds = [minX, minY, maxX, maxY];
  671. }
  672. function packData(mesh) {
  673. var i, ii, j, jj;
  674. var coords = mesh.coords;
  675. var coordsPacked = new Float32Array(coords.length * 2);
  676. for (i = 0, j = 0, ii = coords.length; i < ii; i++) {
  677. var xy = coords[i];
  678. coordsPacked[j++] = xy[0];
  679. coordsPacked[j++] = xy[1];
  680. }
  681. mesh.coords = coordsPacked;
  682. var colors = mesh.colors;
  683. var colorsPacked = new Uint8Array(colors.length * 3);
  684. for (i = 0, j = 0, ii = colors.length; i < ii; i++) {
  685. var c = colors[i];
  686. colorsPacked[j++] = c[0];
  687. colorsPacked[j++] = c[1];
  688. colorsPacked[j++] = c[2];
  689. }
  690. mesh.colors = colorsPacked;
  691. var figures = mesh.figures;
  692. for (i = 0, ii = figures.length; i < ii; i++) {
  693. var figure = figures[i],
  694. ps = figure.coords,
  695. cs = figure.colors;
  696. for (j = 0, jj = ps.length; j < jj; j++) {
  697. ps[j] *= 2;
  698. cs[j] *= 3;
  699. }
  700. }
  701. }
  702. function Mesh(stream, matrix, xref, res) {
  703. assert(isStream(stream), 'Mesh data is not a stream');
  704. var dict = stream.dict;
  705. this.matrix = matrix;
  706. this.shadingType = dict.get('ShadingType');
  707. this.type = 'Pattern';
  708. this.bbox = dict.getArray('BBox');
  709. var cs = dict.get('ColorSpace', 'CS');
  710. cs = ColorSpace.parse(cs, xref, res);
  711. this.cs = cs;
  712. this.background = dict.has('Background') ? cs.getRgb(dict.get('Background'), 0) : null;
  713. var fnObj = dict.get('Function');
  714. var fn = fnObj ? PDFFunction.parseArray(xref, fnObj) : null;
  715. this.coords = [];
  716. this.colors = [];
  717. this.figures = [];
  718. var decodeContext = {
  719. bitsPerCoordinate: dict.get('BitsPerCoordinate'),
  720. bitsPerComponent: dict.get('BitsPerComponent'),
  721. bitsPerFlag: dict.get('BitsPerFlag'),
  722. decode: dict.getArray('Decode'),
  723. colorFn: fn,
  724. colorSpace: cs,
  725. numComps: fn ? 1 : cs.numComps
  726. };
  727. var reader = new MeshStreamReader(stream, decodeContext);
  728. var patchMesh = false;
  729. switch (this.shadingType) {
  730. case ShadingType.FREE_FORM_MESH:
  731. decodeType4Shading(this, reader);
  732. break;
  733. case ShadingType.LATTICE_FORM_MESH:
  734. var verticesPerRow = dict.get('VerticesPerRow') | 0;
  735. assert(verticesPerRow >= 2, 'Invalid VerticesPerRow');
  736. decodeType5Shading(this, reader, verticesPerRow);
  737. break;
  738. case ShadingType.COONS_PATCH_MESH:
  739. decodeType6Shading(this, reader);
  740. patchMesh = true;
  741. break;
  742. case ShadingType.TENSOR_PATCH_MESH:
  743. decodeType7Shading(this, reader);
  744. patchMesh = true;
  745. break;
  746. default:
  747. error('Unsupported mesh type.');
  748. break;
  749. }
  750. if (patchMesh) {
  751. updateBounds(this);
  752. for (var i = 0, ii = this.figures.length; i < ii; i++) {
  753. buildFigureFromPatch(this, i);
  754. }
  755. }
  756. updateBounds(this);
  757. packData(this);
  758. }
  759. Mesh.prototype = {
  760. getIR: function Mesh_getIR() {
  761. return ['Mesh', this.shadingType, this.coords, this.colors, this.figures, this.bounds, this.matrix, this.bbox, this.background];
  762. }
  763. };
  764. return Mesh;
  765. }();
  766. Shadings.Dummy = function DummyClosure() {
  767. function Dummy() {
  768. this.type = 'Pattern';
  769. }
  770. Dummy.prototype = {
  771. getIR: function Dummy_getIR() {
  772. return ['Dummy'];
  773. }
  774. };
  775. return Dummy;
  776. }();
  777. function getTilingPatternIR(operatorList, dict, args) {
  778. var matrix = dict.getArray('Matrix');
  779. var bbox = dict.getArray('BBox');
  780. var xstep = dict.get('XStep');
  781. var ystep = dict.get('YStep');
  782. var paintType = dict.get('PaintType');
  783. var tilingType = dict.get('TilingType');
  784. return ['TilingPattern', args, operatorList, matrix, bbox, xstep, ystep, paintType, tilingType];
  785. }
  786. exports.Pattern = Pattern;
  787. exports.getTilingPatternIR = getTilingPatternIR;