]> git.parisson.com Git - pdf.js.git/commitdiff
Implemented type 2 shading for the pdf (aka gradients)
authorsbarman <sbarman@L3CWZ5T.(none)>
Tue, 14 Jun 2011 18:55:27 +0000 (11:55 -0700)
committersbarman <sbarman@L3CWZ5T.(none)>
Tue, 14 Jun 2011 18:57:02 +0000 (11:57 -0700)
pdf.js

diff --git a/pdf.js b/pdf.js
index 418db2462e228f6cff7627c40d205f0fae5cf73e..87335317a1658e2803a48cb513ffb8ba80de26f8 100644 (file)
--- a/pdf.js
+++ b/pdf.js
@@ -1911,14 +1911,19 @@ var CanvasGraphics = (function() {
 
         // Shading
         shadingFill: function(entryRef) {
+            if (!this.current.bbox)
+                TODO("bbox");
+
             var shadingRes = this.res.get("Shading");
             if (!shadingRes)
                 return;
-            shadingRes = this.xref.fetchIfRef(shadingRes);
+
+            var xref = this.xref;
+            shadingRes = xref.fetchIfRef(shadingRes);
             var shading = shadingRes.get(entryRef.name);
             if (!shading)
                 return;
-            shading = this.xref.fetchIfRef(shading);
+            shading = xref.fetchIfRef(shading);
             if (!shading)
                 return;
 
@@ -1931,8 +1936,13 @@ var CanvasGraphics = (function() {
                 this.endPath();
             }
 
+            var cs = shading.get2("ColorSpace", "CS");
             TODO("shading-fill color space");
 
+            var background = shading.get("Background");
+            if (background)
+                TODO("handle background colors");
+
             var type = shading.get("ShadingType");
             switch (type) {
             case 1:
@@ -1952,10 +1962,10 @@ var CanvasGraphics = (function() {
 
             this.restore();
         },
+
         fillAxialShading: function(sh) {
-            var coordsArr = sh.get("Coords");
-            var x0 = coordsArr[0], y0 = coordsArr[1],
-                x1 = coordsArr[2], y1 = coordsArr[3];
+            var cds = sh.get("Coords");
+
 
             var t0 = 0.0, t1 = 1.0;
             if (sh.has("Domain")) {
@@ -1967,19 +1977,29 @@ var CanvasGraphics = (function() {
             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 (!IsFunction(fnObj))
+                error("invalid function");
+            fn = new Function(this.xref, fnObj);
+
+            var gradient = this.ctx.createLinearGradient(cds[0], cds[1], cds[2], cds[3]);
+            var step = (t1 - t0) / 10;
+            
+            for (var i = t0; i <= t1; i += step) {
+                var c = fn.func([i]);
+                var clength = c.length;
+                for (var j = 0; j < clength; ++j)
+                    c[j] = Math.round(c[j] * 255);
+                gradient.addColorStop(i, "rgb("+c[0] + "," + c[1] + "," + c[2] + ")");
             }
-
-            var fn = sh.get("Function");
-            fn = this.xref.fetchIfRef(fn);
-
-            var gradient = this.ctx.createLinearGradient(x0, y0, x1, y1);
-
-            gradient.addColorStop(0, 'rgb(0,0,255)');
-            gradient.addColorStop(1, 'rgb(0,255,0)');
 
             this.ctx.fillStyle = gradient;
-            this.ctx.fill();
-            this.consumePath();
+            
+            // HACK to draw the gradient onto an infinite rectangle
+            this.ctx.fillRect(-1e10, -1e10, 2e10, 2e10);
         },
 
         // XObjects
@@ -2292,3 +2312,162 @@ var ColorSpace = (function() {
 
     return constructor;
 })();
+
+var Function = (function() {
+    function constructor(xref, fn) {
+        var dict = fn.dict;
+        if (!dict)
+           dict = fn;
+
+        var type = dict.get("FunctionType");
+
+        switch(type) {
+        case 0:
+            this.constructSampled(fn, dict);
+            break;
+        case 2:
+            this.constructInterpolated();
+            break;
+        case 3:
+            this.constructStiched();
+            break;
+        case 4:
+            this.constructPostScript();
+            break;
+        default:
+            error("Unknown type of function");
+        }
+    };
+
+    constructor.prototype = {
+        constructSampled: function(str, dict) {
+            var domain = dict.get("Domain");
+            var range = dict.get("Range");
+
+            if (!domain || !range)
+                error("No domain or range");
+        
+            var inputSize = domain.length / 2;
+            var outputSize = range.length / 2;
+
+            if (inputSize != 1)
+                error("No support for multi-variable inputs to functions");
+
+            var size = dict.get("Size");
+            var bps = dict.get("BitsPerSample");
+            var order = dict.get("Order");
+            if (!order)
+                order = 1;
+            if (order !== 1)
+                error ("No support for cubic spline interpolation");
+            
+            var encode = dict.get("Encode");
+            if (!encode) {
+                encode = [];
+                for (var i = 0; i < inputSize; ++i) {
+                    encode.push(0);
+                    encode.push(size[i] - 1);
+                }
+            }
+            var decode = dict.get("Decode");
+            if (!decode)
+                decode = range;
+
+            var samples = this.getSampleArray(size, outputSize, bps, str);
+
+            this.func = function(args) {
+                var clip = function(v, min, max) {
+                    if (v > max)
+                        v = max;
+                    else if (v < min)
+                        v = min
+                    return v;
+                }
+
+                if (inputSize != args.length)
+                    error("Incorrect number of arguments");
+
+                for (var i = 0; i < inputSize; i++) {
+                    var i2 = i * 2;
+                    
+                    // clip to the domain
+                    var v = clip(args[i], domain[i2], domain[i2 + 1]);
+
+                    // encode
+                    v = encode[i2] + ((v - domain[i2]) * 
+                            (encode[i2 + 1] - encode[i2]) / 
+                            (domain[i2 + 1] - domain[i2]));
+                    
+                    // clip to the size
+                    args[i] = clip(v, 0, size[i] - 1);
+                }
+
+                // interpolate to table
+                TODO("Multi-dimensional interpolation");
+                var floor = Math.floor(args[0]);
+                var ceil = Math.ceil(args[0]);
+                var scale = args[0] - floor;
+
+                floor *= outputSize;
+                ceil *= outputSize;
+
+                var output = [];
+                for (var i = 0; i < outputSize; ++i) {
+                    if (ceil == floor) {
+                        var v = samples[ceil + i];
+                    } else {
+                        var low = samples[floor + i];
+                        var high = samples[ceil + i];
+                        var v = low * scale + high * (1 - scale);
+                    }
+                    
+                    var i2 = i * 2;
+                    // decode
+                    v = decode[i2] + (v * (decode[i2 + 1] - decode[i2]) / 
+                            ((1 << bps) - 1));
+                    
+                    // clip to the domain
+                    output.push(clip(v, range[i2], range[i2 + 1]));
+                }
+
+                return output;
+            }
+        },
+        getSampleArray: function(size, outputSize, bps, str) {
+            var length = 1;
+            for (var i = 0; i < size.length; i++)
+                length *= size[i];
+            length *= outputSize;
+
+            var array = [];
+            var codeSize = 0;
+            var codeBuf = 0;
+
+            var strBytes = str.getBytes((length * bps + 7) / 8);
+            var strIdx = 0;
+            for (var i = 0; i < length; i++) {
+                var b;
+                while (codeSize < bps) {
+                    codeBuf <<= 8;
+                    codeBuf |= strBytes[strIdx++];
+                    codeSize += 8;
+                }
+                codeSize -= bps
+                array.push(codeBuf >> codeSize);
+                codeBuf &= (1 << codeSize) - 1;
+            }
+            return array;
+        },
+        constructInterpolated: function() {
+            error("unhandled type of function");
+        },    
+        constructStiched: function() {
+            error("unhandled type of function");
+        },    
+        constructPostScript: function() {
+            error("unhandled type of function");
+        }
+    };
+
+    return constructor;
+})();