Merge pull request #265 from sbarman/patternfix
Fix to gradient and tiling colorspaces
This commit is contained in:
		
						commit
						736f2e9ea1
					
				
							
								
								
									
										747
									
								
								pdf.js
									
									
									
									
									
								
							
							
						
						
									
										747
									
								
								pdf.js
									
									
									
									
									
								
							| @ -3851,7 +3851,7 @@ var PartialEvaluator = (function() { | |||||||
| // <canvas> contexts store most of the state we need natively.
 | // <canvas> contexts store most of the state we need natively.
 | ||||||
| // However, PDF needs a bit more state, which we store here.
 | // However, PDF needs a bit more state, which we store here.
 | ||||||
| var CanvasExtraState = (function() { | var CanvasExtraState = (function() { | ||||||
|   function constructor() { |   function constructor(old) { | ||||||
|     // Are soft masks and alpha values shapes or opacities?
 |     // Are soft masks and alpha values shapes or opacities?
 | ||||||
|     this.alphaIsShape = false; |     this.alphaIsShape = false; | ||||||
|     this.fontSize = 0; |     this.fontSize = 0; | ||||||
| @ -3868,10 +3868,18 @@ var CanvasExtraState = (function() { | |||||||
|     this.wordSpace = 0; |     this.wordSpace = 0; | ||||||
|     this.textHScale = 100; |     this.textHScale = 100; | ||||||
|     // Color spaces
 |     // Color spaces
 | ||||||
|     this.fillColorSpace = null; |     this.fillColorSpaceObj = null; | ||||||
|     this.strokeColorSpace = null; |     this.strokeColorSpaceObj = null; | ||||||
|  |     this.fillColorObj = null; | ||||||
|  |     this.strokeColorObj = null; | ||||||
|  | 
 | ||||||
|  |     this.old = old; | ||||||
|   } |   } | ||||||
|  | 
 | ||||||
|   constructor.prototype = { |   constructor.prototype = { | ||||||
|  |     clone: function canvasextra_clone() { | ||||||
|  |       return Object.create(this); | ||||||
|  |     } | ||||||
|   }; |   }; | ||||||
|   return constructor; |   return constructor; | ||||||
| })(); | })(); | ||||||
| @ -3902,9 +3910,6 @@ var CanvasGraphics = (function() { | |||||||
|   var NORMAL_CLIP = {}; |   var NORMAL_CLIP = {}; | ||||||
|   var EO_CLIP = {}; |   var EO_CLIP = {}; | ||||||
| 
 | 
 | ||||||
|   // Used for tiling patterns
 |  | ||||||
|   var PAINT_TYPE_COLORED = 1, PAINT_TYPE_UNCOLORED = 2; |  | ||||||
| 
 |  | ||||||
|   constructor.prototype = { |   constructor.prototype = { | ||||||
|     beginDrawing: function(mediaBox) { |     beginDrawing: function(mediaBox) { | ||||||
|       var cw = this.ctx.canvas.width, ch = this.ctx.canvas.height; |       var cw = this.ctx.canvas.width, ch = this.ctx.canvas.height; | ||||||
| @ -3967,8 +3972,9 @@ var CanvasGraphics = (function() { | |||||||
|       if (this.ctx.$saveCurrentX) { |       if (this.ctx.$saveCurrentX) { | ||||||
|         this.ctx.$saveCurrentX(); |         this.ctx.$saveCurrentX(); | ||||||
|       } |       } | ||||||
|       this.stateStack.push(this.current); |       var old = this.current; | ||||||
|       this.current = new CanvasExtraState(); |       this.stateStack.push(old); | ||||||
|  |       this.current = old.clone(); | ||||||
|     }, |     }, | ||||||
|     restore: function() { |     restore: function() { | ||||||
|       var prev = this.stateStack.pop(); |       var prev = this.stateStack.pop(); | ||||||
| @ -4007,7 +4013,19 @@ var CanvasGraphics = (function() { | |||||||
|       this.ctx.rect(x, y, width, height); |       this.ctx.rect(x, y, width, height); | ||||||
|     }, |     }, | ||||||
|     stroke: function() { |     stroke: function() { | ||||||
|       this.ctx.stroke(); |       var ctx = this.ctx; | ||||||
|  |       var strokeColor = this.current.strokeColor; | ||||||
|  |       if (strokeColor && strokeColor.type === "Pattern") { | ||||||
|  |         // for patterns, we transform to pattern space, calculate
 | ||||||
|  |         // the pattern, call stroke, and restore to user space
 | ||||||
|  |         ctx.save(); | ||||||
|  |         ctx.strokeStyle = strokeColor.getPattern(ctx); | ||||||
|  |         ctx.stroke(); | ||||||
|  |         ctx.restore(); | ||||||
|  |       } else { | ||||||
|  |         ctx.stroke(); | ||||||
|  |       } | ||||||
|  | 
 | ||||||
|       this.consumePath(); |       this.consumePath(); | ||||||
|     }, |     }, | ||||||
|     closeStroke: function() { |     closeStroke: function() { | ||||||
| @ -4015,7 +4033,18 @@ var CanvasGraphics = (function() { | |||||||
|       this.stroke(); |       this.stroke(); | ||||||
|     }, |     }, | ||||||
|     fill: function() { |     fill: function() { | ||||||
|       this.ctx.fill(); |       var ctx = this.ctx; | ||||||
|  |       var fillColor = this.current.fillColor; | ||||||
|  | 
 | ||||||
|  |       if (fillColor && fillColor.type === "Pattern") { | ||||||
|  |         ctx.save(); | ||||||
|  |         ctx.fillStyle = fillColor.getPattern(ctx); | ||||||
|  |         ctx.fill(); | ||||||
|  |         ctx.restore(); | ||||||
|  |       } else { | ||||||
|  |         ctx.fill(); | ||||||
|  |       } | ||||||
|  | 
 | ||||||
|       this.consumePath(); |       this.consumePath(); | ||||||
|     }, |     }, | ||||||
|     eoFill: function() { |     eoFill: function() { | ||||||
| @ -4024,8 +4053,28 @@ var CanvasGraphics = (function() { | |||||||
|       this.restoreFillRule(savedFillRule); |       this.restoreFillRule(savedFillRule); | ||||||
|     }, |     }, | ||||||
|     fillStroke: function() { |     fillStroke: function() { | ||||||
|       this.ctx.fill(); |       var ctx = this.ctx; | ||||||
|       this.ctx.stroke(); | 
 | ||||||
|  |       var fillColor = this.current.fillColor; | ||||||
|  |       if (fillColor && fillColor.type === "Pattern") { | ||||||
|  |         ctx.save(); | ||||||
|  |         ctx.fillStyle = fillColor.getPattern(ctx); | ||||||
|  |         ctx.fill(); | ||||||
|  |         ctx.restore(); | ||||||
|  |       } else { | ||||||
|  |         ctx.fill(); | ||||||
|  |       } | ||||||
|  |        | ||||||
|  |       var strokeColor = this.current.strokeColor; | ||||||
|  |       if (strokeColor && strokeColor.type === "Pattern") { | ||||||
|  |         ctx.save(); | ||||||
|  |         ctx.strokeStyle = strokeColor.getPattern(ctx); | ||||||
|  |         ctx.stroke(); | ||||||
|  |         ctx.restore(); | ||||||
|  |       } else { | ||||||
|  |         ctx.stroke(); | ||||||
|  |       } | ||||||
|  |        | ||||||
|       this.consumePath(); |       this.consumePath(); | ||||||
|     }, |     }, | ||||||
|     eoFillStroke: function() { |     eoFillStroke: function() { | ||||||
| @ -4208,168 +4257,41 @@ var CanvasGraphics = (function() { | |||||||
|           ColorSpace.parse(space, this.xref, this.res); |           ColorSpace.parse(space, this.xref, this.res); | ||||||
|     }, |     }, | ||||||
|     setStrokeColor: function(/*...*/) { |     setStrokeColor: function(/*...*/) { | ||||||
|       var cs = this.getStrokeColorSpace(); |       var cs = this.current.strokeColorSpace; | ||||||
|       var color = cs.getRgb(arguments); |       var color = cs.getRgb(arguments); | ||||||
|       this.setStrokeRGBColor.apply(this, color); |       this.setStrokeRGBColor.apply(this, color); | ||||||
|     }, |     }, | ||||||
|     setStrokeColorN: function(/*...*/) { |     setStrokeColorN: function(/*...*/) { | ||||||
|       var cs = this.getStrokeColorSpace(); |       var cs = this.current.strokeColorSpace; | ||||||
| 
 | 
 | ||||||
|       if (cs.name == 'Pattern') { |       if (cs.name == 'Pattern') { | ||||||
|         this.ctx.strokeStyle = this.getPattern(cs, arguments); |         // wait until fill to actually get the pattern, since Canvas
 | ||||||
|  |         // calcualtes the pattern according to the current coordinate space,
 | ||||||
|  |         // not the space when the pattern is set.
 | ||||||
|  |         var pattern = Pattern.parse(arguments, cs, this.xref, this.res, | ||||||
|  |                                     this.ctx); | ||||||
|  |         this.current.strokeColor = pattern; | ||||||
|       } else { |       } else { | ||||||
|         this.setStrokeColor.apply(this, arguments); |         this.setStrokeColor.apply(this, arguments); | ||||||
|       } |       } | ||||||
|     }, |     }, | ||||||
|     setFillColor: function(/*...*/) { |     setFillColor: function(/*...*/) { | ||||||
|       var cs = this.getFillColorSpace(); |       var cs = this.current.fillColorSpace; | ||||||
|       var color = cs.getRgb(arguments); |       var color = cs.getRgb(arguments); | ||||||
|       this.setFillRGBColor.apply(this, color); |       this.setFillRGBColor.apply(this, color); | ||||||
|     }, |     }, | ||||||
|     setFillColorN: function(/*...*/) { |     setFillColorN: function(/*...*/) { | ||||||
|       var cs = this.getFillColorSpace(); |       var cs = this.current.fillColorSpace; | ||||||
| 
 | 
 | ||||||
|       if (cs.name == 'Pattern') { |       if (cs.name == 'Pattern') { | ||||||
|         this.ctx.fillStyle = this.getPattern(cs, arguments); |         // wait until fill to actually get the pattern
 | ||||||
|  |         var pattern = Pattern.parse(arguments, cs, this.xref, this.res, | ||||||
|  |                                     this.ctx); | ||||||
|  |         this.current.fillColor = pattern; | ||||||
|       } else { |       } else { | ||||||
|         this.setFillColor.apply(this, arguments); |         this.setFillColor.apply(this, arguments); | ||||||
|       } |       } | ||||||
|     }, |     }, | ||||||
|     getPattern: function(cs, args) { |  | ||||||
|       var length = args.length; |  | ||||||
|       var base = cs.base; |  | ||||||
|       if (base) { |  | ||||||
|         var baseComps = base.numComps; |  | ||||||
| 
 |  | ||||||
|         var color = []; |  | ||||||
|         for (var i = 0; i < baseComps; ++i) |  | ||||||
|           color.push(args[i]); |  | ||||||
| 
 |  | ||||||
|         color = base.getRgb(color); |  | ||||||
|       } |  | ||||||
| 
 |  | ||||||
|       var patternName = args[length - 1]; |  | ||||||
|       if (!IsName(patternName)) |  | ||||||
|         error("Bad args to getPattern"); |  | ||||||
| 
 |  | ||||||
|       var xref = this.xref; |  | ||||||
|       var patternRes = xref.fetchIfRef(this.res.get("Pattern")); |  | ||||||
|       if (!patternRes) |  | ||||||
|         error("Unable to find pattern resource"); |  | ||||||
| 
 |  | ||||||
|       var pattern = xref.fetchIfRef(patternRes.get(patternName.name)); |  | ||||||
|       var dict = IsStream(pattern) ? pattern.dict : pattern; |  | ||||||
| 
 |  | ||||||
|       var types = [null, this.getTilingPattern, this.getShadingPattern]; |  | ||||||
| 
 |  | ||||||
|       var typeNum = dict.get("PatternType"); |  | ||||||
|       var patternFn = types[typeNum]; |  | ||||||
|       if (!patternFn) |  | ||||||
|         error("Unhandled pattern type"); |  | ||||||
|       return patternFn.call(this, pattern, dict, color); |  | ||||||
|     }, |  | ||||||
|     getShadingPattern: function(pattern, dict) { |  | ||||||
|       var matrix = dict.get("Matrix"); |  | ||||||
|        |  | ||||||
|       this.save(); |  | ||||||
|       this.transform.apply(this, matrix); |  | ||||||
|       var shading = this.getShading(pattern.get("Shading")); |  | ||||||
|       this.restore(); |  | ||||||
| 
 |  | ||||||
|       TODO('store transform so it can be applied before every fill'); |  | ||||||
|       return shading; |  | ||||||
|     }, |  | ||||||
|     getTilingPattern: function(pattern, dict, color) { |  | ||||||
|       function multiply(m, tm) { |  | ||||||
|         var a = m[0] * tm[0] + m[1] * tm[2]; |  | ||||||
|         var b = m[0] * tm[1] + m[1] * tm[3]; |  | ||||||
|         var c = m[2] * tm[0] + m[3] * tm[2]; |  | ||||||
|         var d = m[2] * tm[1] + m[3] * tm[3]; |  | ||||||
|         var e = m[4] * tm[0] + m[5] * tm[2] + tm[4]; |  | ||||||
|         var f = m[4] * tm[1] + m[5] * tm[3] + tm[5]; |  | ||||||
|         return [a, b, c, d, e, f]; |  | ||||||
|       }; |  | ||||||
| 
 |  | ||||||
|       this.save(); |  | ||||||
|       var ctx = this.ctx; |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
|       TODO('TilingType'); |  | ||||||
| 
 |  | ||||||
|       var matrix = dict.get('Matrix') || IDENTITY_MATRIX; |  | ||||||
| 
 |  | ||||||
|       var bbox = dict.get('BBox'); |  | ||||||
|       var x0 = bbox[0], y0 = bbox[1], x1 = bbox[2], y1 = bbox[3]; |  | ||||||
| 
 |  | ||||||
|       var xstep = dict.get('XStep'); |  | ||||||
|       var ystep = dict.get('YStep'); |  | ||||||
| 
 |  | ||||||
|       // top left corner should correspond to the top left of the bbox
 |  | ||||||
|       var topLeft = this.applyTransform(x0, y0, matrix); |  | ||||||
|       // we want the canvas to be as large as the step size
 |  | ||||||
|       var botRight = this.applyTransform(x0 + xstep, y0 + ystep, matrix); |  | ||||||
| 
 |  | ||||||
|       var width = botRight[0] - topLeft[0]; |  | ||||||
|       var height = botRight[1] - topLeft[1]; |  | ||||||
| 
 |  | ||||||
|       // TODO: hack to avoid OOM, remove then pattern code is fixed
 |  | ||||||
|       if (Math.abs(width) > 8192 || Math.abs(height) > 8192) { |  | ||||||
|         this.restore(); |  | ||||||
|         return 'hotpink'; |  | ||||||
|       } |  | ||||||
| 
 |  | ||||||
|       var tmpCanvas = new this.ScratchCanvas(width, height); |  | ||||||
| 
 |  | ||||||
|       // set the new canvas element context as the graphics context
 |  | ||||||
|       var tmpCtx = tmpCanvas.getContext('2d'); |  | ||||||
|       var savedCtx = ctx; |  | ||||||
|       this.ctx = tmpCtx; |  | ||||||
| 
 |  | ||||||
|       var paintType = dict.get('PaintType'); |  | ||||||
|       switch (paintType) { |  | ||||||
|       case PAINT_TYPE_COLORED: |  | ||||||
|         tmpCtx.fillStyle = savedCtx.fillStyle; |  | ||||||
|         tmpCtx.strokeStyle = savedCtx.strokeStyle; |  | ||||||
|         break; |  | ||||||
|       case PAINT_TYPE_UNCOLORED: |  | ||||||
|         color = this.makeCssRgb.apply(this, color); |  | ||||||
|         tmpCtx.fillStyle = color; |  | ||||||
|         tmpCtx.strokeStyle = color; |  | ||||||
|         break; |  | ||||||
|       default: |  | ||||||
|         error('Unsupported paint type'); |  | ||||||
|       } |  | ||||||
| 
 |  | ||||||
|       // normalize transform matrix so each step
 |  | ||||||
|       // takes up the entire tmpCanvas (need to remove white borders)
 |  | ||||||
|       if (matrix[1] === 0 && matrix[2] === 0) { |  | ||||||
|         matrix[0] = tmpCanvas.width / xstep; |  | ||||||
|         matrix[3] = tmpCanvas.height / ystep; |  | ||||||
|         topLeft = this.applyTransform(x0, y0, matrix); |  | ||||||
|       } |  | ||||||
| 
 |  | ||||||
|       // move the top left corner of bounding box to [0,0]
 |  | ||||||
|       matrix = multiply(matrix, [1, 0, 0, 1, -topLeft[0], -topLeft[1]]); |  | ||||||
|        |  | ||||||
|       this.transform.apply(this, matrix); |  | ||||||
| 
 |  | ||||||
|       if (bbox && IsArray(bbox) && 4 == bbox.length) { |  | ||||||
|         this.rectangle.apply(this, bbox); |  | ||||||
|         this.clip(); |  | ||||||
|         this.endPath(); |  | ||||||
|       } |  | ||||||
| 
 |  | ||||||
|       var xref = this.xref; |  | ||||||
|       var res = xref.fetchIfRef(dict.get('Resources')); |  | ||||||
|       if (!pattern.code) |  | ||||||
|         pattern.code = this.compile(pattern, xref, res, []); |  | ||||||
|       this.execute(pattern.code, xref, res); |  | ||||||
| 
 |  | ||||||
|       this.ctx = savedCtx; |  | ||||||
|       this.restore(); |  | ||||||
| 
 |  | ||||||
|       return this.ctx.createPattern(tmpCanvas, 'repeat'); |  | ||||||
|     }, |  | ||||||
|     setStrokeGray: function(gray) { |     setStrokeGray: function(gray) { | ||||||
|       this.setStrokeRGBColor(gray, gray, gray); |       this.setStrokeRGBColor(gray, gray, gray); | ||||||
|     }, |     }, | ||||||
| @ -4377,16 +4299,24 @@ var CanvasGraphics = (function() { | |||||||
|       this.setFillRGBColor(gray, gray, gray); |       this.setFillRGBColor(gray, gray, gray); | ||||||
|     }, |     }, | ||||||
|     setStrokeRGBColor: function(r, g, b) { |     setStrokeRGBColor: function(r, g, b) { | ||||||
|       this.ctx.strokeStyle = this.makeCssRgb(r, g, b); |       var color = Util.makeCssRgb(r, g, b); | ||||||
|  |       this.ctx.strokeStyle = color; | ||||||
|  |       this.current.strokeColor = color; | ||||||
|     }, |     }, | ||||||
|     setFillRGBColor: function(r, g, b) { |     setFillRGBColor: function(r, g, b) { | ||||||
|       this.ctx.fillStyle = this.makeCssRgb(r, g, b); |       var color = Util.makeCssRgb(r, g, b); | ||||||
|  |       this.ctx.fillStyle = color; | ||||||
|  |       this.current.fillColor = color; | ||||||
|     }, |     }, | ||||||
|     setStrokeCMYKColor: function(c, m, y, k) { |     setStrokeCMYKColor: function(c, m, y, k) { | ||||||
|       this.ctx.strokeStyle = this.makeCssCmyk(c, m, y, k); |       var color = Util.makeCssCmyk(c, m, y, k); | ||||||
|  |       this.ctx.strokeStyle = color; | ||||||
|  |       this.current.strokeColor = color; | ||||||
|     }, |     }, | ||||||
|     setFillCMYKColor: function(c, m, y, k) { |     setFillCMYKColor: function(c, m, y, k) { | ||||||
|       this.ctx.fillStyle = this.makeCssCmyk(c, m, y, k); |       var color = Util.makeCssCmyk(c, m, y, k); | ||||||
|  |       this.ctx.fillStyle = color; | ||||||
|  |       this.current.fillColor = color; | ||||||
|     }, |     }, | ||||||
| 
 | 
 | ||||||
|     // Shading
 |     // Shading
 | ||||||
| @ -4403,10 +4333,10 @@ var CanvasGraphics = (function() { | |||||||
|       if (!shading) |       if (!shading) | ||||||
|         error('No shading object found'); |         error('No shading object found'); | ||||||
| 
 | 
 | ||||||
|       var shadingFill = this.getShading(shading); |       var shadingFill = Pattern.parseShading(shading, null, xref, res, ctx); | ||||||
| 
 | 
 | ||||||
|       this.save(); |       this.save(); | ||||||
|       ctx.fillStyle = shadingFill; |       ctx.fillStyle = shadingFill.getPattern(); | ||||||
| 
 | 
 | ||||||
|       var inv = ctx.mozCurrentTransformInverse; |       var inv = ctx.mozCurrentTransformInverse; | ||||||
|       if (inv) { |       if (inv) { | ||||||
| @ -4414,10 +4344,10 @@ var CanvasGraphics = (function() { | |||||||
|         var width = canvas.width; |         var width = canvas.width; | ||||||
|         var height = canvas.height; |         var height = canvas.height; | ||||||
| 
 | 
 | ||||||
|         var bl = this.applyTransform(0, 0, inv); |         var bl = Util.applyTransform([0, 0], inv); | ||||||
|         var br = this.applyTransform(0, width, inv); |         var br = Util.applyTransform([0, width], inv); | ||||||
|         var ul = this.applyTransform(height, 0, inv); |         var ul = Util.applyTransform([height, 0], inv); | ||||||
|         var ur = this.applyTransform(height, width, inv); |         var ur = Util.applyTransform([height, width], inv); | ||||||
| 
 | 
 | ||||||
|         var x0 = Math.min(bl[0], br[0], ul[0], ur[0]); |         var x0 = Math.min(bl[0], br[0], ul[0], ur[0]); | ||||||
|         var y0 = Math.min(bl[1], br[1], ul[1], ur[1]); |         var y0 = Math.min(bl[1], br[1], ul[1], ur[1]); | ||||||
| @ -4437,129 +4367,6 @@ var CanvasGraphics = (function() { | |||||||
| 
 | 
 | ||||||
|       this.restore(); |       this.restore(); | ||||||
|     }, |     }, | ||||||
|     getShading: function(shading) { |  | ||||||
|       this.save(); |  | ||||||
|        |  | ||||||
|       shading = this.xref.fetchIfRef(shading); |  | ||||||
|       var dict = IsStream(shading) ? shading.dict : shading; |  | ||||||
| 
 |  | ||||||
|       var bbox = dict.get('BBox'); |  | ||||||
|       if (bbox && IsArray(bbox) && 4 == bbox.length) { |  | ||||||
|         this.rectangle.apply(this, bbox); |  | ||||||
|         this.clip(); |  | ||||||
|         this.endPath(); |  | ||||||
|       } |  | ||||||
| 
 |  | ||||||
|       var background = dict.get('Background'); |  | ||||||
|       if (background) |  | ||||||
|         TODO('handle background colors'); |  | ||||||
| 
 |  | ||||||
|       var cs = dict.get('ColorSpace', 'CS'); |  | ||||||
|       cs = ColorSpace.parse(cs, this.xref, this.res); |  | ||||||
| 
 |  | ||||||
|       var types = [null, |  | ||||||
|           null, |  | ||||||
|           this.getAxialShading, |  | ||||||
|           this.getRadialShading]; |  | ||||||
| 
 |  | ||||||
|       var typeNum = dict.get('ShadingType'); |  | ||||||
|       var shadingFn = types[typeNum]; |  | ||||||
|        |  | ||||||
|       this.restore(); |  | ||||||
| 
 |  | ||||||
|       // Most likely we will not implement other types of shading
 |  | ||||||
|       // unless the browser supports them
 |  | ||||||
|       if (!shadingFn) { |  | ||||||
|         warn("Unknown or NYI type of shading '"+ typeNum +"'"); |  | ||||||
|         return 'hotpink'; |  | ||||||
|       } |  | ||||||
| 
 |  | ||||||
|       return shadingFn.call(this, shading, cs); |  | ||||||
|     }, |  | ||||||
|     getAxialShading: function(sh, cs) { |  | ||||||
|       var coordsArr = sh.get('Coords'); |  | ||||||
|       var x0 = coordsArr[0], y0 = coordsArr[1], |  | ||||||
|           x1 = coordsArr[2], y1 = coordsArr[3]; |  | ||||||
| 
 |  | ||||||
|       var t0 = 0.0, t1 = 1.0; |  | ||||||
|       if (sh.has('Domain')) { |  | ||||||
|         var domainArr = sh.get('Domain'); |  | ||||||
|         t0 = domainArr[0], t1 = domainArr[1]; |  | ||||||
|       } |  | ||||||
| 
 |  | ||||||
|       var extendStart = false, extendEnd = false; |  | ||||||
|       if (sh.has('Extend')) { |  | ||||||
|         var extendArr = sh.get('Extend'); |  | ||||||
|         extendStart = extendArr[0], extendEnd = extendArr[1]; |  | ||||||
|         TODO('Support extend'); |  | ||||||
|       } |  | ||||||
|       var fnObj = sh.get('Function'); |  | ||||||
|       fnObj = this.xref.fetchIfRef(fnObj); |  | ||||||
|       if (IsArray(fnObj)) |  | ||||||
|         error('No support for array of functions'); |  | ||||||
|       else if (!IsPDFFunction(fnObj)) |  | ||||||
|         error('Invalid function'); |  | ||||||
|       var fn = new PDFFunction(this.xref, fnObj); |  | ||||||
| 
 |  | ||||||
|       var gradient = this.ctx.createLinearGradient(x0, y0, x1, y1); |  | ||||||
| 
 |  | ||||||
|       // 10 samples seems good enough for now, but probably won't work
 |  | ||||||
|       // if there are sharp color changes. Ideally, we would implement
 |  | ||||||
|       // the spec faithfully and add lossless optimizations.
 |  | ||||||
|       var step = (t1 - t0) / 10; |  | ||||||
|       var diff = t1 - t0; |  | ||||||
| 
 |  | ||||||
|       for (var i = t0; i <= t1; i += step) { |  | ||||||
|         var color = fn.func([i]); |  | ||||||
|         var rgbColor = cs.getRgb(color); |  | ||||||
|         gradient.addColorStop((i - t0) / diff, |  | ||||||
|             this.makeCssRgb.apply(this, rgbColor)); |  | ||||||
|       } |  | ||||||
| 
 |  | ||||||
|       return gradient; |  | ||||||
|     }, |  | ||||||
|     getRadialShading: function(sh, cs) { |  | ||||||
|       var coordsArr = sh.get('Coords'); |  | ||||||
|       var x0 = coordsArr[0], y0 = coordsArr[1], r0 = coordsArr[2]; |  | ||||||
|       var x1 = coordsArr[3], y1 = coordsArr[4], r1 = coordsArr[5]; |  | ||||||
| 
 |  | ||||||
|       var t0 = 0.0, t1 = 1.0; |  | ||||||
|       if (sh.has('Domain')) { |  | ||||||
|         var domainArr = sh.get('Domain'); |  | ||||||
|         t0 = domainArr[0], t1 = domainArr[1]; |  | ||||||
|       } |  | ||||||
| 
 |  | ||||||
|       var extendStart = false, extendEnd = false; |  | ||||||
|       if (sh.has('Extend')) { |  | ||||||
|         var extendArr = sh.get('Extend'); |  | ||||||
|         extendStart = extendArr[0], extendEnd = extendArr[1]; |  | ||||||
|         TODO('Support extend'); |  | ||||||
|       } |  | ||||||
|       var fnObj = sh.get('Function'); |  | ||||||
|       fnObj = this.xref.fetchIfRef(fnObj); |  | ||||||
|       if (IsArray(fnObj)) |  | ||||||
|         error('No support for array of functions'); |  | ||||||
|       else if (!IsPDFFunction(fnObj)) |  | ||||||
|         error('Invalid function'); |  | ||||||
|       var fn = new PDFFunction(this.xref, fnObj); |  | ||||||
| 
 |  | ||||||
|       var gradient =  |  | ||||||
|         this.ctx.createRadialGradient(x0, y0, r0, x1, y1, r1); |  | ||||||
| 
 |  | ||||||
|       // 10 samples seems good enough for now, but probably won't work
 |  | ||||||
|       // if there are sharp color changes. Ideally, we would implement
 |  | ||||||
|       // the spec faithfully and add lossless optimizations.
 |  | ||||||
|       var step = (t1 - t0) / 10; |  | ||||||
|       var diff = t1 - t0; |  | ||||||
| 
 |  | ||||||
|       for (var i = t0; i <= t1; i += step) { |  | ||||||
|         var color = fn.func([i]); |  | ||||||
|         var rgbColor = cs.getRgb(color); |  | ||||||
|         gradient.addColorStop((i - t0) / diff,  |  | ||||||
|             this.makeCssRgb.apply(this, rgbColor)); |  | ||||||
|       } |  | ||||||
|       return gradient; |  | ||||||
|     }, |  | ||||||
| 
 | 
 | ||||||
|     // Images
 |     // Images
 | ||||||
|     beginInlineImage: function() { |     beginInlineImage: function() { | ||||||
| @ -4698,48 +4505,6 @@ var CanvasGraphics = (function() { | |||||||
|       } |       } | ||||||
|       this.ctx.beginPath(); |       this.ctx.beginPath(); | ||||||
|     }, |     }, | ||||||
|     makeCssRgb: function(r, g, b) { |  | ||||||
|       var ri = (255 * r) | 0, gi = (255 * g) | 0, bi = (255 * b) | 0; |  | ||||||
|       return 'rgb(' + ri + ',' + gi + ',' + bi + ')'; |  | ||||||
|     }, |  | ||||||
|     makeCssCmyk: function(c, m, y, k) { |  | ||||||
|       // while waiting on CSS's cmyk()...
 |  | ||||||
|       // http://www.ilkeratalay.com/colorspacesfaq.php#rgb
 |  | ||||||
|       var ri = (255 * (1 - Math.min(1, c * (1 - k) + k))) | 0; |  | ||||||
|       var gi = (255 * (1 - Math.min(1, m * (1 - k) + k))) | 0; |  | ||||||
|       var bi = (255 * (1 - Math.min(1, y * (1 - k) + k))) | 0; |  | ||||||
|       return 'rgb(' + ri + ',' + gi + ',' + bi + ')'; |  | ||||||
|     }, |  | ||||||
|     getFillColorSpace: function() { |  | ||||||
|       var cs = this.current.fillColorSpace; |  | ||||||
|       if (cs) |  | ||||||
|         return cs; |  | ||||||
| 
 |  | ||||||
|       var states = this.stateStack; |  | ||||||
|       var i = states.length - 1; |  | ||||||
|       while (i >= 0 && !(cs = states[i].fillColorSpace)) |  | ||||||
|         --i; |  | ||||||
| 
 |  | ||||||
|       if (cs) |  | ||||||
|         return cs; |  | ||||||
|       else |  | ||||||
|         return new DeviceRgbCS(); |  | ||||||
|     }, |  | ||||||
|     getStrokeColorSpace: function() { |  | ||||||
|       var cs = this.current.strokeColorSpace; |  | ||||||
|       if (cs) |  | ||||||
|         return cs; |  | ||||||
| 
 |  | ||||||
|       var states = this.stateStack; |  | ||||||
|       var i = states.length - 1; |  | ||||||
|       while (i >= 0 && !(cs = states[i].strokeColorSpace)) |  | ||||||
|         --i; |  | ||||||
| 
 |  | ||||||
|       if (cs) |  | ||||||
|         return cs; |  | ||||||
|       else |  | ||||||
|         return new DeviceRgbCS(); |  | ||||||
|     }, |  | ||||||
|     // We generally keep the canvas context set for
 |     // We generally keep the canvas context set for
 | ||||||
|     // nonzero-winding, and just set evenodd for the operations
 |     // nonzero-winding, and just set evenodd for the operations
 | ||||||
|     // that need them.
 |     // that need them.
 | ||||||
| @ -4751,16 +4516,31 @@ var CanvasGraphics = (function() { | |||||||
|     restoreFillRule: function(rule) { |     restoreFillRule: function(rule) { | ||||||
|       this.ctx.mozFillRule = rule; |       this.ctx.mozFillRule = rule; | ||||||
|     }, |     }, | ||||||
|     applyTransform: function(x0, y0, m) { |  | ||||||
|       var xt = x0 * m[0] + y0 * m[2] + m[4]; |  | ||||||
|       var yt = x0 * m[1] + y0 * m[3] + m[5]; |  | ||||||
|       return [xt, yt]; |  | ||||||
|     } |  | ||||||
|   }; |   }; | ||||||
| 
 | 
 | ||||||
|   return constructor; |   return constructor; | ||||||
| })(); | })(); | ||||||
| 
 | 
 | ||||||
|  | var Util = (function() { | ||||||
|  |   function constructor() {}; | ||||||
|  |   constructor.makeCssRgb = function makergb(r, g, b) { | ||||||
|  |     var ri = (255 * r) | 0, gi = (255 * g) | 0, bi = (255 * b) | 0; | ||||||
|  |     return 'rgb(' + ri + ',' + gi + ',' + bi + ')'; | ||||||
|  |   }; | ||||||
|  |   constructor.makeCssCmyk = function makecmyk(c, m, y, k) { | ||||||
|  |     var c = (new DeviceCmykCS()).getRgb([c, m, y, k]); | ||||||
|  |     var ri = (255 * c[0]) | 0, gi = (255 * c[1]) | 0, bi = (255 * c[2]) | 0; | ||||||
|  |     return 'rgb(' + ri + ',' + gi + ',' + bi + ')'; | ||||||
|  |   }; | ||||||
|  |   constructor.applyTransform = function apply(p, m) { | ||||||
|  |     var xt = p[0] * m[0] + p[1] * m[2] + m[4]; | ||||||
|  |     var yt = p[0] * m[1] + p[1] * m[3] + m[5]; | ||||||
|  |     return [xt, yt]; | ||||||
|  |   }; | ||||||
|  |    | ||||||
|  |   return constructor; | ||||||
|  | })(); | ||||||
|  | 
 | ||||||
| var ColorSpace = (function() { | var ColorSpace = (function() { | ||||||
|   // Constructor should define this.numComps, this.defaultColor, this.name
 |   // Constructor should define this.numComps, this.defaultColor, this.name
 | ||||||
|   function constructor() { |   function constructor() { | ||||||
| @ -5112,6 +4892,307 @@ var DeviceCmykCS = (function() { | |||||||
|   return constructor; |   return constructor; | ||||||
| })(); | })(); | ||||||
| 
 | 
 | ||||||
|  | var Pattern = (function() { | ||||||
|  |   // Constructor should define this.getPattern
 | ||||||
|  |   function constructor() { | ||||||
|  |     error('should not call Pattern constructor'); | ||||||
|  |   }; | ||||||
|  | 
 | ||||||
|  |   constructor.prototype = { | ||||||
|  |     // Input: current Canvas context
 | ||||||
|  |     // Output: the appropriate fillStyle or strokeStyle
 | ||||||
|  |     getPattern: function pattern_getStyle(ctx) { | ||||||
|  |       error('Should not call Pattern.getStyle'); | ||||||
|  |     }, | ||||||
|  |   }; | ||||||
|  | 
 | ||||||
|  |   constructor.parse = function pattern_parse(args, cs, xref, res, ctx) { | ||||||
|  |     var length = args.length; | ||||||
|  | 
 | ||||||
|  |     var patternName = args[length - 1]; | ||||||
|  |     if (!IsName(patternName)) | ||||||
|  |       error("Bad args to getPattern"); | ||||||
|  | 
 | ||||||
|  |     var patternRes = xref.fetchIfRef(res.get("Pattern")); | ||||||
|  |     if (!patternRes) | ||||||
|  |       error("Unable to find pattern resource"); | ||||||
|  | 
 | ||||||
|  |     var pattern = xref.fetchIfRef(patternRes.get(patternName.name)); | ||||||
|  |     var dict = IsStream(pattern) ? pattern.dict : pattern; | ||||||
|  |     var typeNum = dict.get("PatternType"); | ||||||
|  | 
 | ||||||
|  |     switch(typeNum) { | ||||||
|  |     case 1: | ||||||
|  |       var base = cs.base; | ||||||
|  |       var color; | ||||||
|  |       if (base) { | ||||||
|  |         var baseComps = base.numComps; | ||||||
|  | 
 | ||||||
|  |         color = []; | ||||||
|  |         for (var i = 0; i < baseComps; ++i) | ||||||
|  |           color.push(args[i]); | ||||||
|  | 
 | ||||||
|  |         color = base.getRgb(color); | ||||||
|  |       } | ||||||
|  |       return new TilingPattern(pattern, dict, color, xref, ctx); | ||||||
|  |     case 2: | ||||||
|  |       var shading = xref.fetchIfRef(dict.get('Shading')); | ||||||
|  |       var matrix = dict.get('Matrix'); | ||||||
|  |       return Pattern.parseShading(shading, matrix, xref, res, ctx); | ||||||
|  |     default: | ||||||
|  |       error('Unknown type of pattern'); | ||||||
|  |     } | ||||||
|  |   }; | ||||||
|  | 
 | ||||||
|  |   constructor.parseShading = function pattern_shading(shading, matrix, | ||||||
|  |       xref, res, ctx) { | ||||||
|  | 
 | ||||||
|  |     var dict = IsStream(shading) ? shading.dict : shading; | ||||||
|  |     var type = dict.get('ShadingType'); | ||||||
|  | 
 | ||||||
|  |     switch (type) { | ||||||
|  |     case 2: | ||||||
|  |     case 3: | ||||||
|  |       // both radial and axial shadings are handled by RadialAxial shading
 | ||||||
|  |       return new RadialAxialShading(dict, matrix, xref, res, ctx); | ||||||
|  |     default: | ||||||
|  |       return new DummyShading(); | ||||||
|  |     } | ||||||
|  |   } | ||||||
|  |   return constructor; | ||||||
|  | })(); | ||||||
|  | 
 | ||||||
|  | var DummyShading = (function() { | ||||||
|  |   function constructor() { | ||||||
|  |     this.type = 'Pattern'; | ||||||
|  |   }; | ||||||
|  |   constructor.prototype = { | ||||||
|  |     getPattern: function dummy_getpattern() { | ||||||
|  |       return 'hotpink'; | ||||||
|  |     } | ||||||
|  |   }; | ||||||
|  |   return constructor; | ||||||
|  | })(); | ||||||
|  | 
 | ||||||
|  | // Radial and axial shading have very similar implementations
 | ||||||
|  | // If needed, the implementations can be broken into two classes
 | ||||||
|  | var RadialAxialShading = (function() { | ||||||
|  |   function constructor(dict, matrix, xref, res, ctx) { | ||||||
|  |     this.matrix = matrix; | ||||||
|  |     var bbox = dict.get('BBox'); | ||||||
|  |     var background = dict.get('Background'); | ||||||
|  |     this.coordsArr = dict.get('Coords'); | ||||||
|  |     this.shadingType = dict.get('ShadingType'); | ||||||
|  |     this.type = 'Pattern'; | ||||||
|  | 
 | ||||||
|  |     this.ctx = ctx; | ||||||
|  |     this.curMatrix = ctx.mozCurrentTransform; | ||||||
|  | 
 | ||||||
|  |     var cs = dict.get('ColorSpace', 'CS'); | ||||||
|  |     cs = ColorSpace.parse(cs, xref, res); | ||||||
|  |     this.cs = cs; | ||||||
|  | 
 | ||||||
|  |     var t0 = 0.0, t1 = 1.0; | ||||||
|  |     if (dict.has('Domain')) { | ||||||
|  |       var domainArr = dict.get('Domain'); | ||||||
|  |       t0 = domainArr[0], t1 = domainArr[1]; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     var extendStart = false, extendEnd = false; | ||||||
|  |     if (dict.has('Extend')) { | ||||||
|  |       var extendArr = dict.get('Extend'); | ||||||
|  |       extendStart = extendArr[0], extendEnd = extendArr[1]; | ||||||
|  |       TODO('Support extend'); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     this.extendStart = extendStart; | ||||||
|  |     this.extendEnd = extendEnd; | ||||||
|  | 
 | ||||||
|  |     var fnObj = dict.get('Function'); | ||||||
|  |     fnObj = xref.fetchIfRef(fnObj); | ||||||
|  |     if (IsArray(fnObj)) | ||||||
|  |       error('No support for array of functions'); | ||||||
|  |     else if (!IsPDFFunction(fnObj)) | ||||||
|  |       error('Invalid function'); | ||||||
|  |     var fn = new PDFFunction(xref, fnObj); | ||||||
|  | 
 | ||||||
|  |     // 10 samples seems good enough for now, but probably won't work
 | ||||||
|  |     // if there are sharp color changes. Ideally, we would implement
 | ||||||
|  |     // the spec faithfully and add lossless optimizations.
 | ||||||
|  |     var step = (t1 - t0) / 10; | ||||||
|  |     var diff = t1 - t0; | ||||||
|  | 
 | ||||||
|  |     var colorStops = []; | ||||||
|  |     for (var i = t0; i <= t1; i += step) { | ||||||
|  |       var color = fn.func([i]); | ||||||
|  |       var rgbColor = Util.makeCssRgb.apply(this, cs.getRgb(color)); | ||||||
|  |       colorStops.push([(i - t0) / diff, rgbColor]); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     this.colorStops = colorStops; | ||||||
|  |   }; | ||||||
|  | 
 | ||||||
|  |   constructor.prototype = { | ||||||
|  |     getPattern: function() { | ||||||
|  |       var coordsArr = this.coordsArr; | ||||||
|  |       var type = this.shadingType; | ||||||
|  |       if (type == 2) { | ||||||
|  |         var p0 = [coordsArr[0], coordsArr[1]]; | ||||||
|  |         var p1 = [coordsArr[2], coordsArr[3]]; | ||||||
|  |       } else if (type == 3) { | ||||||
|  |         var p0 = [coordsArr[0], coordsArr[1]]; | ||||||
|  |         var p1 = [coordsArr[3], coordsArr[4]]; | ||||||
|  |         var r0 = coordsArr[2], r1 = coordsArr[5] | ||||||
|  |       } else { | ||||||
|  |         error() | ||||||
|  |       } | ||||||
|  | 
 | ||||||
|  |       var matrix = this.matrix; | ||||||
|  |       if (matrix) { | ||||||
|  |         p0 = Util.applyTransform(p0, matrix); | ||||||
|  |         p1 = Util.applyTransform(p1, matrix); | ||||||
|  |       } | ||||||
|  | 
 | ||||||
|  |       // if the browser supports getting the tranform matrix, convert
 | ||||||
|  |       // gradient coordinates from pattern space to current user space
 | ||||||
|  |       var curMatrix = this.curMatrix; | ||||||
|  |       var ctx = this.ctx; | ||||||
|  |       if (curMatrix) { | ||||||
|  |         var userMatrix = ctx.mozCurrentTransformInverse; | ||||||
|  | 
 | ||||||
|  |         p0 = Util.applyTransform(p0, curMatrix); | ||||||
|  |         p0 = Util.applyTransform(p0, userMatrix); | ||||||
|  | 
 | ||||||
|  |         p1 = Util.applyTransform(p1, curMatrix); | ||||||
|  |         p1 = Util.applyTransform(p1, userMatrix); | ||||||
|  |       } | ||||||
|  | 
 | ||||||
|  |       var colorStops = this.colorStops; | ||||||
|  |       if (type == 2) | ||||||
|  |         var grad = ctx.createLinearGradient(p0[0], p0[1], p1[0], p1[1]); | ||||||
|  |       else if (type == 3) | ||||||
|  |         var grad = ctx.createRadialGradient(p0[0], p0[1], r0, p1[0], p1[1], r1); | ||||||
|  | 
 | ||||||
|  |       for (var i = 0, ii = colorStops.length; i < ii; ++i) { | ||||||
|  |         var c = colorStops[i]; | ||||||
|  |         grad.addColorStop(c[0], c[1]); | ||||||
|  |       } | ||||||
|  |       return grad; | ||||||
|  |     } | ||||||
|  |   }; | ||||||
|  |   return constructor; | ||||||
|  | })(); | ||||||
|  | 
 | ||||||
|  | var TilingPattern = (function() { | ||||||
|  |   var PAINT_TYPE_COLORED = 1, PAINT_TYPE_UNCOLORED = 2; | ||||||
|  |    | ||||||
|  |   function constructor(pattern, dict, color, xref, ctx) { | ||||||
|  |       function multiply(m, tm) { | ||||||
|  |         var a = m[0] * tm[0] + m[1] * tm[2]; | ||||||
|  |         var b = m[0] * tm[1] + m[1] * tm[3]; | ||||||
|  |         var c = m[2] * tm[0] + m[3] * tm[2]; | ||||||
|  |         var d = m[2] * tm[1] + m[3] * tm[3]; | ||||||
|  |         var e = m[4] * tm[0] + m[5] * tm[2] + tm[4]; | ||||||
|  |         var f = m[4] * tm[1] + m[5] * tm[3] + tm[5]; | ||||||
|  |         return [a, b, c, d, e, f]; | ||||||
|  |       }; | ||||||
|  | 
 | ||||||
|  |       TODO('TilingType'); | ||||||
|  | 
 | ||||||
|  |       this.matrix = dict.get("Matrix"); | ||||||
|  |       this.curMatrix = ctx.mozCurrentTransform; | ||||||
|  |       this.invMatrix = ctx.mozCurrentTransformInverse; | ||||||
|  |       this.ctx = ctx; | ||||||
|  |       this.type = 'Pattern'; | ||||||
|  | 
 | ||||||
|  |       var bbox = dict.get('BBox'); | ||||||
|  |       var x0 = bbox[0], y0 = bbox[1], x1 = bbox[2], y1 = bbox[3]; | ||||||
|  | 
 | ||||||
|  |       var xstep = dict.get('XStep'); | ||||||
|  |       var ystep = dict.get('YStep'); | ||||||
|  | 
 | ||||||
|  |       var topLeft = [x0, y0]; | ||||||
|  |       // we want the canvas to be as large as the step size
 | ||||||
|  |       var botRight = [x0 + xstep, y0 + ystep] | ||||||
|  | 
 | ||||||
|  |       var width = botRight[0] - topLeft[0]; | ||||||
|  |       var height = botRight[1] - topLeft[1]; | ||||||
|  | 
 | ||||||
|  |       // TODO: hack to avoid OOM, we would idealy compute the tiling
 | ||||||
|  |       // pattern to be only as large as the acual size in device space
 | ||||||
|  |       // This could be computed with .mozCurrentTransform, but still 
 | ||||||
|  |       // needs to be implemented
 | ||||||
|  |       while (Math.abs(width) > 512 || Math.abs(height) > 512) { | ||||||
|  |         width = 512; | ||||||
|  |         height = 512; | ||||||
|  |       } | ||||||
|  | 
 | ||||||
|  |       var tmpCanvas = new ScratchCanvas(width, height); | ||||||
|  | 
 | ||||||
|  |       // set the new canvas element context as the graphics context
 | ||||||
|  |       var tmpCtx = tmpCanvas.getContext('2d'); | ||||||
|  |       var graphics = new CanvasGraphics(tmpCtx); | ||||||
|  | 
 | ||||||
|  |       var paintType = dict.get('PaintType'); | ||||||
|  |       switch (paintType) { | ||||||
|  |       case PAINT_TYPE_COLORED: | ||||||
|  |         tmpCtx.fillStyle = ctx.fillStyle; | ||||||
|  |         tmpCtx.strokeStyle = ctx.strokeStyle; | ||||||
|  |         break; | ||||||
|  |       case PAINT_TYPE_UNCOLORED: | ||||||
|  |         color = Util.makeCssRgb.apply(this, color); | ||||||
|  |         tmpCtx.fillStyle = color; | ||||||
|  |         tmpCtx.strokeStyle = color; | ||||||
|  |         break; | ||||||
|  |       default: | ||||||
|  |         error('Unsupported paint type'); | ||||||
|  |       } | ||||||
|  | 
 | ||||||
|  |       var scale = [width / xstep, height / ystep]; | ||||||
|  |       this.scale = scale; | ||||||
|  | 
 | ||||||
|  |       // transform coordinates to pattern space
 | ||||||
|  |       var tmpTranslate = [1, 0, 0, 1, -topLeft[0], -topLeft[1]]; | ||||||
|  |       var tmpScale = [scale[0], 0, 0, scale[1], 0, 0]; | ||||||
|  |       graphics.transform.apply(graphics, tmpScale); | ||||||
|  |       graphics.transform.apply(graphics, tmpTranslate); | ||||||
|  | 
 | ||||||
|  |       if (bbox && IsArray(bbox) && 4 == bbox.length) { | ||||||
|  |         graphics.rectangle.apply(graphics, bbox); | ||||||
|  |         graphics.clip(); | ||||||
|  |         graphics.endPath(); | ||||||
|  |       } | ||||||
|  | 
 | ||||||
|  |       var res = xref.fetchIfRef(dict.get('Resources')); | ||||||
|  |       if (!pattern.code) | ||||||
|  |         pattern.code = graphics.compile(pattern, xref, res, []); | ||||||
|  |       graphics.execute(pattern.code, xref, res); | ||||||
|  | 
 | ||||||
|  |       this.canvas = tmpCanvas; | ||||||
|  |   }; | ||||||
|  | 
 | ||||||
|  |   constructor.prototype = { | ||||||
|  |     getPattern: function tiling_getPattern() { | ||||||
|  |       var matrix = this.matrix; | ||||||
|  |       var curMatrix = this.curMatrix; | ||||||
|  |       var ctx = this.ctx; | ||||||
|  | 
 | ||||||
|  |       if (curMatrix) | ||||||
|  |         ctx.setTransform.apply(ctx, curMatrix); | ||||||
|  | 
 | ||||||
|  |       if (matrix) | ||||||
|  |         ctx.transform.apply(ctx, matrix); | ||||||
|  | 
 | ||||||
|  |       var scale = this.scale; | ||||||
|  |       ctx.scale(1 / scale[0], 1 / scale[1]); | ||||||
|  | 
 | ||||||
|  |       return ctx.createPattern(this.canvas, 'repeat'); | ||||||
|  |     } | ||||||
|  |   }; | ||||||
|  |   return constructor; | ||||||
|  | })(); | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
| var PDFImage = (function() { | var PDFImage = (function() { | ||||||
|   function constructor(xref, res, image, inline) { |   function constructor(xref, res, image, inline) { | ||||||
|     this.image = image; |     this.image = image; | ||||||
|  | |||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user