pattern.js 24 KB

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