Skip to content

Commit

Permalink
Draw <img> elements
Browse files Browse the repository at this point in the history
  • Loading branch information
niklasvh committed Jan 26, 2014
1 parent 2afdcaf commit 74cb346
Show file tree
Hide file tree
Showing 7 changed files with 157 additions and 39 deletions.
8 changes: 4 additions & 4 deletions Gruntfile.js
Original file line number Diff line number Diff line change
Expand Up @@ -50,10 +50,10 @@ module.exports = function(grunt) {
},
watch: {
files: 'src/**/*',
tasks: ['build', 'jshint']
tasks: ['jshint', 'build']
},
jshint: {
all: ['<%= concat.dist.dest %>'],
all: ['src/**/*.js', '!src/promise.js'],
options: grunt.file.readJSON('./.jshintrc')
}
});
Expand All @@ -80,7 +80,7 @@ module.exports = function(grunt) {
// Default task.
grunt.registerTask('server', ['connect']);
grunt.registerTask('build', ['concat', 'uglify']);
grunt.registerTask('default', ['concat', 'jshint', 'qunit', 'uglify']);
grunt.registerTask('travis', ['concat', 'jshint', 'qunit', 'uglify', 'webdriver']);
grunt.registerTask('default', ['jshint', 'concat', 'qunit', 'uglify']);
grunt.registerTask('travis', ['jshint', 'concat','qunit', 'uglify', 'webdriver']);

};
95 changes: 77 additions & 18 deletions build/html2canvas.js
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ window.html2canvas = function(nodeList, options) {
var renderer = new CanvasRenderer(documentWidth(), documentHeight(), imageLoader);
var parser = new NodeParser(node, renderer, support, imageLoader, options);

window.console.log(parser);
window.console.log(parser);
});
};

Expand Down Expand Up @@ -77,6 +77,7 @@ function createWindowClone(ownerDocument, width, height) {
documentClone.close();

documentClone.replaceChild(documentClone.adoptNode(documentElement), documentClone.documentElement);
container.contentWindow.scrollTo(window.scrollX, window.scrollY);
var div = documentClone.createElement("div");
div.className = "html2canvas-ready-test";
documentClone.body.appendChild(div);
Expand Down Expand Up @@ -259,10 +260,14 @@ NodeParser.prototype.parse = function(stack) {
};

NodeParser.prototype.paint = function(container) {
if (isTextNode(container)) {
this.paintText(container);
} else {
this.paintNode(container);
try {
if (isTextNode(container)) {
this.paintText(container);
} else {
this.paintNode(container);
}
} catch(e) {
log(e);
}
};

Expand All @@ -277,6 +282,17 @@ NodeParser.prototype.paintNode = function(container) {
this.renderer.renderBackground(container, bounds);
}, this);
this.renderer.renderBorders(borderData.borders);

switch(container.node.nodeName) {
case "IMG":
var imageContainer = this.images.get(container.node.src);
if (imageContainer) {
this.renderer.renderImage(container, bounds, borderData, imageContainer.image);
} else {
log("Error loading <img>", container.node.src);
}
break;
}
};

NodeParser.prototype.paintText = function(container) {
Expand Down Expand Up @@ -613,10 +629,23 @@ function ImageLoader(options, support) {
this.origin = window.location.protocol + window.location.host;
}

ImageLoader.prototype.findImages = function(images, container) {
var backgrounds = container.parseBackgroundImages();
var backgroundImages = backgrounds.filter(this.isImageBackground).map(this.getBackgroundUrl).filter(this.imageExists(images)).map(this.loadImage, this);
return images.concat(backgroundImages);
ImageLoader.prototype.findImages = function(nodes) {
var images = [];
nodes.filter(isImage).map(src).forEach(this.addImage(images, this.loadImage), this);
return images;
};

ImageLoader.prototype.findBackgroundImage = function(images, container) {
container.parseBackgroundImages().filter(this.isImageBackground).map(this.getBackgroundUrl).forEach(this.addImage(images, this.loadImage), this);
return images;
};

ImageLoader.prototype.addImage = function(images, callback) {
return function(newImage) {
if (!this.imageExists(images, newImage)) {
images.splice(0, 0, callback.apply(this, arguments));
}
};
};

ImageLoader.prototype.getBackgroundUrl = function(imageData) {
Expand All @@ -641,12 +670,10 @@ ImageLoader.prototype.loadImage = function(src) {
}
};

ImageLoader.prototype.imageExists = function(images) {
return function(newImage) {
return !images.some(function(image) {
return image.src !== newImage.src;
});
};
ImageLoader.prototype.imageExists = function(images, src) {
return images.some(function(image) {
return image.src === src;
});
};

ImageLoader.prototype.isSameOrigin = function(url) {
Expand All @@ -669,11 +696,19 @@ ImageLoader.prototype.get = function(src) {
};

ImageLoader.prototype.fetch = function(nodes) {
this.images = nodes.reduce(bind(this.findImages, this), []);
this.images = nodes.reduce(bind(this.findBackgroundImage, this), this.findImages(nodes));
this.ready = Promise.all(this.images.map(this.getPromise));
return this;
};

function isImage(container) {
return container.node.nodeName === "IMG";
}

function src(container) {
return container.node.src;
}

function log() {
if (window.html2canvas.logging && window.console && window.console.log) {
window.console.log.apply(window.console, [(Date.now() - window.html2canvas.start) + "ms", "html2canvas:"].concat([].slice.call(arguments, 0)));
Expand Down Expand Up @@ -931,6 +966,26 @@ function Renderer(width, height, images) {
this.images = images;
}

Renderer.prototype.renderImage = function(container, bounds, borderData, image) {
var paddingLeft = container.cssInt('paddingLeft'),
paddingTop = container.cssInt('paddingTop'),
paddingRight = container.cssInt('paddingRight'),
paddingBottom = container.cssInt('paddingBottom'),
borders = borderData.borders;

this.drawImage(
image,
0,
0,
image.width,
image.height,
bounds.left + paddingLeft + borders[3].width,
bounds.top + paddingTop + borders[0].width,
bounds.width - (borders[1].width + borders[3].width + paddingLeft + paddingRight),
bounds.height - (borders[0].width + borders[2].width + paddingTop + paddingBottom)
);
};

Renderer.prototype.renderBackground = function(container, bounds) {
if (bounds.height > 0 && bounds.width > 0) {
this.renderBackgroundColor(container, bounds);
Expand Down Expand Up @@ -965,7 +1020,7 @@ Renderer.prototype.renderBackgroundImage = function(container, bounds) {
} else {
log("Error loading background-image", backgroundImage.args[0]);
}
}
}
}, this);
};

Expand Down Expand Up @@ -1021,6 +1076,10 @@ CanvasRenderer.prototype.drawShape = function(shape, color) {
this.setFillStyle(color).fill();
};

CanvasRenderer.prototype.drawImage = function(image, sx, sy, sw, sh, dx, dy, dw, dh) {
this.ctx.drawImage(image, sx, sy, sw, sh, dx, dy, dw, dh);
};

CanvasRenderer.prototype.clip = function(shape, callback, context) {
this.ctx.save();
this.shape(shape).clip();
Expand Down Expand Up @@ -1057,7 +1116,7 @@ CanvasRenderer.prototype.backgroundRepeatShape = function(imageContainer, backgr
["line", Math.round(left), Math.round(height + top)]
];
this.clip(shape, function() {
this.renderBackgroundRepeat(imageContainer, backgroundPosition, bounds);
this.renderBackgroundRepeat(imageContainer, backgroundPosition, size, bounds);
}, this);
};

Expand Down
2 changes: 1 addition & 1 deletion build/html2canvas.min.js

Large diffs are not rendered by default.

24 changes: 20 additions & 4 deletions src/core.js
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,7 @@ function createWindowClone(ownerDocument, width, height) {
documentClone.close();

documentClone.replaceChild(documentClone.adoptNode(documentElement), documentClone.documentElement);
container.contentWindow.scrollTo(window.scrollX, window.scrollY);
var div = documentClone.createElement("div");
div.className = "html2canvas-ready-test";
documentClone.body.appendChild(div);
Expand Down Expand Up @@ -250,10 +251,14 @@ NodeParser.prototype.parse = function(stack) {
};

NodeParser.prototype.paint = function(container) {
if (isTextNode(container)) {
this.paintText(container);
} else {
this.paintNode(container);
try {
if (isTextNode(container)) {
this.paintText(container);
} else {
this.paintNode(container);
}
} catch(e) {
log(e);
}
};

Expand All @@ -268,6 +273,17 @@ NodeParser.prototype.paintNode = function(container) {
this.renderer.renderBackground(container, bounds);
}, this);
this.renderer.renderBorders(borderData.borders);

switch(container.node.nodeName) {
case "IMG":
var imageContainer = this.images.get(container.node.src);
if (imageContainer) {
this.renderer.renderImage(container, bounds, borderData, imageContainer.image);
} else {
log("Error loading <img>", container.node.src);
}
break;
}
};

NodeParser.prototype.paintText = function(container) {
Expand Down
41 changes: 30 additions & 11 deletions src/imageloader.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,23 @@ function ImageLoader(options, support) {
this.origin = window.location.protocol + window.location.host;
}

ImageLoader.prototype.findImages = function(images, container) {
var backgrounds = container.parseBackgroundImages();
var backgroundImages = backgrounds.filter(this.isImageBackground).map(this.getBackgroundUrl).filter(this.imageExists(images)).map(this.loadImage, this);
return images.concat(backgroundImages);
ImageLoader.prototype.findImages = function(nodes) {
var images = [];
nodes.filter(isImage).map(src).forEach(this.addImage(images, this.loadImage), this);
return images;
};

ImageLoader.prototype.findBackgroundImage = function(images, container) {
container.parseBackgroundImages().filter(this.isImageBackground).map(this.getBackgroundUrl).forEach(this.addImage(images, this.loadImage), this);
return images;
};

ImageLoader.prototype.addImage = function(images, callback) {
return function(newImage) {
if (!this.imageExists(images, newImage)) {
images.splice(0, 0, callback.apply(this, arguments));
}
};
};

ImageLoader.prototype.getBackgroundUrl = function(imageData) {
Expand All @@ -33,12 +46,10 @@ ImageLoader.prototype.loadImage = function(src) {
}
};

ImageLoader.prototype.imageExists = function(images) {
return function(newImage) {
return !images.some(function(image) {
return image.src !== newImage.src;
});
};
ImageLoader.prototype.imageExists = function(images, src) {
return images.some(function(image) {
return image.src === src;
});
};

ImageLoader.prototype.isSameOrigin = function(url) {
Expand All @@ -61,7 +72,15 @@ ImageLoader.prototype.get = function(src) {
};

ImageLoader.prototype.fetch = function(nodes) {
this.images = nodes.reduce(bind(this.findImages, this), []);
this.images = nodes.reduce(bind(this.findBackgroundImage, this), this.findImages(nodes));
this.ready = Promise.all(this.images.map(this.getPromise));
return this;
};

function isImage(container) {
return container.node.nodeName === "IMG";
}

function src(container) {
return container.node.src;
}
20 changes: 20 additions & 0 deletions src/renderer.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,26 @@ function Renderer(width, height, images) {
this.images = images;
}

Renderer.prototype.renderImage = function(container, bounds, borderData, image) {
var paddingLeft = container.cssInt('paddingLeft'),
paddingTop = container.cssInt('paddingTop'),
paddingRight = container.cssInt('paddingRight'),
paddingBottom = container.cssInt('paddingBottom'),
borders = borderData.borders;

this.drawImage(
image,
0,
0,
image.width,
image.height,
bounds.left + paddingLeft + borders[3].width,
bounds.top + paddingTop + borders[0].width,
bounds.width - (borders[1].width + borders[3].width + paddingLeft + paddingRight),
bounds.height - (borders[0].width + borders[2].width + paddingTop + paddingBottom)
);
};

Renderer.prototype.renderBackground = function(container, bounds) {
if (bounds.height > 0 && bounds.width > 0) {
this.renderBackgroundColor(container, bounds);
Expand Down
6 changes: 5 additions & 1 deletion src/renderers/canvas.js
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,10 @@ CanvasRenderer.prototype.drawShape = function(shape, color) {
this.setFillStyle(color).fill();
};

CanvasRenderer.prototype.drawImage = function(image, sx, sy, sw, sh, dx, dy, dw, dh) {
this.ctx.drawImage(image, sx, sy, sw, sh, dx, dy, dw, dh);
};

CanvasRenderer.prototype.clip = function(shape, callback, context) {
this.ctx.save();
this.shape(shape).clip();
Expand Down Expand Up @@ -59,7 +63,7 @@ CanvasRenderer.prototype.backgroundRepeatShape = function(imageContainer, backgr
["line", Math.round(left), Math.round(height + top)]
];
this.clip(shape, function() {
this.renderBackgroundRepeat(imageContainer, backgroundPosition, bounds);
this.renderBackgroundRepeat(imageContainer, backgroundPosition, size, bounds);
}, this);
};

Expand Down

0 comments on commit 74cb346

Please sign in to comment.