]> git.parisson.com Git - pdf.js.git/commitdiff
refactored image drawing code
authorsbarman <sbarman@L3CWZ5T.(none)>
Mon, 27 Jun 2011 05:54:18 +0000 (22:54 -0700)
committersbarman <sbarman@L3CWZ5T.(none)>
Mon, 27 Jun 2011 05:54:18 +0000 (22:54 -0700)
pdf.js

diff --git a/pdf.js b/pdf.js
index 2f21c95f09723bd9b869fbbc4b13f465aa4a981e..8b8e6ff54346cbe8823b8fcff75753d2ce604123 100644 (file)
--- a/pdf.js
+++ b/pdf.js
@@ -4234,23 +4234,11 @@ var CanvasGraphics = (function() {
 
         paintImageXObject: function(ref, image, inline) {
             this.save();
-            if (image.getParams) {
-                // JPX/JPEG2000 streams directly contain bits per component
-                // and color space mode information.
-                TODO("get params from actual stream");
-                // var bits = ...
-                // var colorspace = ...
-            }
-            // TODO cache rendered images?
 
+            var ctx = this.ctx;
             var dict = image.dict;
             var w = dict.get2("Width", "W");
             var h = dict.get2("Height", "H");
-
-            if (w < 1 || h < 1)
-                error("Invalid image width or height");
-
-            var ctx = this.ctx;
             // scale the image to the unit square
             ctx.scale(1/w, -1/h);
 
@@ -4265,154 +4253,15 @@ var CanvasGraphics = (function() {
                 return;
             }
 
-            var interpolate = dict.get2("Interpolate", "I");
-            if (!IsBool(interpolate))
-                interpolate = false;
-            var imageMask = dict.get2("ImageMask", "IM");
-            if (!IsBool(imageMask))
-                imageMask = false;
-
-            var bitsPerComponent = image.bitsPerComponent;
-            if (!bitsPerComponent) {
-                bitsPerComponent = dict.get2("BitsPerComponent", "BPC");
-                if (!bitsPerComponent) {
-                    if (imageMask)
-                        bitsPerComponent = 1;
-                    else
-                        error("Bits per component missing in image");
-                }
-            }
-
-            if (bitsPerComponent !== 8) {
-                TODO("Support bpc="+ bitsPerComponent);
-                this.restore();
-                return;
-            }
-
-            var xref = this.xref;
-            var colorSpaces = this.colorSpaces;
-
-            if (imageMask) {
-                error("support image masks");
-            }
-
-            // actual image
-            var csStream = dict.get2("ColorSpace", "CS");
-            csStream = xref.fetchIfRef(csStream);
-            if (IsName(csStream) && inline)
-                csStream = colorSpaces.get(csStream);
-
-            var colorSpace = new ColorSpace(xref, csStream);
-            var decode = dict.get2("Decode", "D");
-
-            TODO("create color map");
-
-            var mask = image.dict.get("Mask");
-            mask = xref.fetchIfRef(mask);
-            var smask = image.dict.get("SMask");
-            smask = xref.fetchIfRef(smask);
-
-            if (IsStream(smask)) {
-                if (inline)
-                    error("cannot combine smask and inlining");
-
-                var maskDict = smask.dict;
-                var maskW = maskDict.get2("Width", "W");
-                var maskH = maskDict.get2("Height", "H");
-                if (!IsNum(maskW) || !IsNum(maskH) || maskW < 1 || maskH < 1)
-                    error("Invalid image width or height");
-                if (maskW !== w || maskH !== h)
-                    error("Invalid image width or height");
-
-                var maskInterpolate = maskDict.get2("Interpolate", "I");
-                if (!IsBool(maskInterpolate))
-                    maskInterpolate = false;
-
-                var maskBPC = maskDict.get2("BitsPerComponent", "BPC");
-                if (!maskBPC)
-                    error("Invalid image mask bpc");
-
-                var maskCsStream = maskDict.get2("ColorSpace", "CS");
-                maskCsStream = xref.fetchIfRef(maskCsStream);
-                var maskColorSpace = new ColorSpace(xref, maskCsStream);
-                if (maskColorSpace.mode !== "DeviceGray")
-                    error("Invalid color space for smask");
-
-                var maskDecode = maskDict.get2("Decode", "D");
-                if (maskDecode)
-                    TODO("Handle mask decode");
-                // handle matte object
-            }
+            var imageObj = new PDFImage(this.xref, this.res, image, inline); 
 
             var tmpCanvas = new this.ScratchCanvas(w, h);
             var tmpCtx = tmpCanvas.getContext("2d");
             var imgData = tmpCtx.getImageData(0, 0, w, h);
             var pixels = imgData.data;
 
-            if (bitsPerComponent != 8)
-                error("unhandled number of bits per component");
-
-            if (smask) {
-                if (maskColorSpace.numComps != 1)
-                    error("Incorrect number of components in smask");
-
-                var numComps = colorSpace.numComps;
-                var imgArray = image.getBytes(numComps * w * h);
-                var imgIdx = 0;
-
-                var smArray = smask.getBytes(w * h);
-                var smIdx = 0;
-
-                var length = 4 * w * h;
-                switch (numComps) {
-                case 1:
-                    for (var i = 0; i < length; i += 4) {
-                        var p = imgArray[imgIdx++];
-                        pixels[i] = p;
-                        pixels[i+1] = p;
-                        pixels[i+2] = p;
-                        pixels[i+3] = smArray[smIdx++];
-                    }
-                    break;
-                case 3:
-                    for (var i = 0; i < length; i += 4) {
-                        pixels[i] = imgArray[imgIdx++];
-                        pixels[i+1] = imgArray[imgIdx++];
-                        pixels[i+2] = imgArray[imgIdx++];
-                        pixels[i+3] = smArray[smIdx++];
-                    }
-                    break;
-                default:
-                    TODO("Images with "+ numComps + " components per pixel");
-                }
-            } else {
-                var numComps = colorSpace.numComps;
-                var imgArray = image.getBytes(numComps * w * h);
-                var imgIdx = 0;
-
-                var length = 4 * w * h;
-                switch (numComps) {
-                case 1:
-                    for (var i = 0; i < length; i += 4) {
-                        var p = imgArray[imgIdx++];
-                        pixels[i] = p;
-                        pixels[i+1] = p;
-                        pixels[i+2] = p;
-                        pixels[i+3] = 255;
-                    }
-                    break;
-                case 3:
-                    for (var i = 0; i < length; i += 4) {
-                        pixels[i] = imgArray[imgIdx++];
-                        pixels[i+1] = imgArray[imgIdx++];
-                        pixels[i+2] = imgArray[imgIdx++];
-                        pixels[i+3] = 255;
-                    }
-                    break;
-                default:
-                    TODO("Images with "+ numComps + " components per pixel");
-                }
-            }
+            imageObj.fillRgbaBuffer(pixels);
+            
             tmpCtx.putImageData(imgData, 0, 0);
             ctx.drawImage(tmpCanvas, 0, -h);
             this.restore();
@@ -4541,6 +4390,169 @@ var ColorSpace = (function() {
     return constructor;
 })();
 
+var PDFImage = (function() {
+    function constructor(xref, res, image, inline) {
+        this.image = image;
+        if (image.getParams) {
+            // JPX/JPEG2000 streams directly contain bits per component
+            // and color space mode information.
+            TODO("get params from actual stream");
+            // var bits = ...
+            // var colorspace = ...
+        }
+        // TODO cache rendered images?
+
+        var dict = image.dict;
+        this.width = dict.get2("Width", "W");
+        this.height = dict.get2("Height", "H");
+
+        if (this.width < 1 || this.height < 1)
+            error("Invalid image width or height");
+
+        this.interpolate = dict.get2("Interpolate", "I") || false;
+        this.imageMask = dict.get2("ImageMask", "IM") || false;
+
+        var bitsPerComponent = image.bitsPerComponent;
+        if (!bitsPerComponent) {
+            bitsPerComponent = dict.get2("BitsPerComponent", "BPC");
+            if (!bitsPerComponent) {
+                if (this.imageMask)
+                    bitsPerComponent = 1;
+                else
+                    error("Bits per component missing in image");
+            }
+        }
+        this.bpc = bitsPerComponent;
+
+        var colorSpaces = res.get("ColorSpace");
+        var csStream = xref.fetchIfRef(dict.get2("ColorSpace", "CS"));
+        if (IsName(csStream) && inline)
+            csStream = colorSpaces.get(csStream);
+        this.colorSpace = new ColorSpace(xref, csStream);
+
+        this.numComps = this.colorSpace.numComps;
+        this.decode = dict.get2("Decode", "D");
+
+        var mask = xref.fetchIfRef(image.dict.get("Mask"));
+        var smask = xref.fetchIfRef(image.dict.get("SMask"));
+
+        if (mask) {
+            TODO("masked images");
+        } else if (smask) {
+            this.smask = new PDFImage(xref, res, smask);
+        }
+    };
+    
+    constructor.prototype = {
+        getCompFunction: function getCompFunction(bpc, width, numComps, buffer) {
+            var bufferPos = 0;
+            if (bpc == 8) {
+                var getComp = function() {
+                    return buffer[bufferPos++];
+                }
+            } else {
+                var rowBytes = (width * numComps * bpc + 7) >> 3;
+                var bits = 0;
+                var buf = 0;
+                var getComp = function() {
+                    while (bits < bpc) {
+                        buf = (buf << 8) | buffer[bufferPos++];
+                        bits += 8;
+                    }
+                    var remainingBits = bits - bpc;
+                    var ret = buf >> remainingBits;
+                    
+                    if (bufferPos % rowBytes == 0) {
+                        buf = 0;
+                        bits = 0;
+                    } else {
+                        buf = buf & ((1 << remainingBits) - 1);
+                        bits = remainingBits;
+                    }
+                    return Math.round(255 * ret / ((1 << bpc) - 1));
+                }
+            }
+            return getComp;
+        },
+        getOpacityFunction: function getOpacityFunction() {
+            var smask = this.smask;
+            if (smask) {
+                var w = smask.width;
+                var h = smask.height;
+                if (w != this.width || h != this.height)
+                    error("smask dimensions do not match image dimensions");
+                
+                var buf = new Uint8Array(w * h);
+                smask.fillGrayBuffer(buf);
+                var bufPos = 0;
+                var opacity = function() {
+                    return buf[bufPos++];
+                }
+            } else {
+                var opacity = function() { return 255; }
+            }
+            return opacity;
+        },
+        fillRgbaBuffer: function fillRgbaBuffer(buffer) {
+            var numComps = this.numComps;
+            var width = this.width;
+            var height = this.height;
+            var bpc = this.bpc;
+
+            // rows start at byte boundary;
+            var rowBytes = (width * numComps * bpc + 7) >> 3;
+            var imgArray = this.image.getBytes(height * rowBytes);
+            var imgPos = 0;
+            
+            var getComp = this.getCompFunction(bpc, width, numComps, imgArray)
+            var getOpacity = this.getOpacityFunction();
+            var length = width * height * 4;
+
+            switch (numComps) {
+                case 1:
+                    for (var i = 0; i < length; i += 4) {
+                        var p = getComp();
+                        buffer[i] = p;
+                        buffer[i+1] = p;
+                        buffer[i+2] = p;
+                        buffer[i+3] = getOpacity();
+                    }
+                    break;
+                case 3:
+                    for (var i = 0; i < length; i += 4) {
+                        buffer[i] = getComp();
+                        buffer[i+1] = getComp();
+                        buffer[i+2] = getComp();
+                        buffer[i+3] = getOpacity();
+                    }
+                    break;
+                default:
+                    TODO("Images with "+ numComps + " components per pixel");
+            }
+        },
+        fillGrayBuffer: function fillGrayScaleBuffer(buffer) {
+            var numComps = this.numComps;
+            if (numComps != 1)
+                error("Reading gray scale from a color image");
+
+            var width = this.width;
+            var height = this.height;
+            var bpc = this.bpc;
+
+            // rows start at byte boundary;
+            var rowBytes = (width * numComps * bpc + 7) >> 3;
+            var imgArray = this.image.getBytes(height * rowBytes);
+            
+            var getComp = this.getCompFunction(bpc, width, numComps, imgArray)
+            var length = width * height;
+
+            for (var i = 0; i < length; ++i)
+                buffer[i] = getComp();
+        },
+    };
+    return constructor;
+})();
+
 var PDFFunction = (function() {
     function constructor(xref, fn) {
         var dict = fn.dict;