Draw <img> elements

This commit is contained in:
Niklas von Hertzen 2014-01-26 18:10:04 +02:00
parent 2afdcaff35
commit 74cb3466ec
7 changed files with 157 additions and 39 deletions

View File

@ -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')
}
});
@ -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']);
};

View File

@ -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);
});
};
@ -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);
@ -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);
}
};
@ -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) {
@ -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) {
@ -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) {
@ -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)));
@ -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);
@ -965,7 +1020,7 @@ Renderer.prototype.renderBackgroundImage = function(container, bounds) {
} else {
log("Error loading background-image", backgroundImage.args[0]);
}
}
}
}, this);
};
@ -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();
@ -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);
};

File diff suppressed because one or more lines are too long

View File

@ -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);
@ -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);
}
};
@ -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) {

View File

@ -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) {
@ -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) {
@ -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;
}

View File

@ -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);

View File

@ -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();
@ -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);
};