关于 用 js 实现 快照功能
Posted 岑惜
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了关于 用 js 实现 快照功能相关的知识,希望对你有一定的参考价值。
1.前言
前段时间有个需求,想要 打印一个小票凭证 ,实现这个功能,我首先想到了快照,
就是将数据内容排版好,然后截图或者用其他方式将内容 制作成图片 ,然后下载下来打印即可。
2.探讨
为何不直接以文件的形式打印呢?原因是用文件排版【包含文字和图片内容】,太复杂了,效果和稳定性不确定,还不如用快照,简单省事,效果也好。
3.效果
【图一】输入动态数据
【图二】js排版,放在一个div里面
【图三】触发生成快照并网页本地下载 ,【如果是要分享,则将图片上传服务器,存储后,获取访问该图片的网址路径,将路径分享即可】
【图四】本地下载的图片文件
【图五】
效果如何?我觉得挺好的,二维码是我后台生成的,用路径获取即可
4.实现原理
其实这都多亏了html2canvas库 ,这是一个js版本操作画布canvas的一个集成库,调用api设置参数即可自定义内容,
问题是,直接使用html2canvas 会导致内容模糊、字迹不清晰等问题,还需要其他的辅助算法才可以制作清晰的快照。
/* html2canvas 0.5.0-beta3 <http://html2canvas.hertzen.com> Copyright (c) 2016 Niklas von Hertzen Released under License */ !function (e) { if ("object" == typeof exports && "undefined" != typeof module) module.exports = e(); else if ("function" == typeof define && define.amd) define([], e); else { var n; "undefined" != typeof window ? n = window : "undefined" != typeof global ? n = global : "undefined" != typeof self && (n = self), n.html2canvas = e() } }(function () { var e; return function n(e, f, o) { function d(t, l) { if (!f[t]) { if (!e[t]) { var s = "function" == typeof require && require; if (!l && s) return s(t, !0); if (i) return i(t, !0); var u = new Error("Cannot find module \'" + t + "\'"); throw u.code = "MODULE_NOT_FOUND", u } var a = f[t] = {exports: {}}; e[t][0].call(a.exports, function (n) { var f = e[t][1][n]; return d(f ? f : n) }, a, a.exports, n, e, f, o) } return f[t].exports } for (var i = "function" == typeof require && require, t = 0; t < o.length; t++) d(o[t]); return d }({ 1: [function (n, f, o) { (function (n) { !function (d) { function i(e) { throw RangeError(I[e]) } function t(e, n) { for (var f = e.length; f--;) e[f] = n(e[f]); return e } function l(e, n) { return t(e.split(H), n).join(".") } function s(e) { for (var n, f, o = [], d = 0, i = e.length; i > d;) n = e.charCodeAt(d++), n >= 55296 && 56319 >= n && i > d ? (f = e.charCodeAt(d++), 56320 == (64512 & f) ? o.push(((1023 & n) << 10) + (1023 & f) + 65536) : (o.push(n), d--)) : o.push(n); return o } function u(e) { return t(e, function (e) { var n = ""; return e > 65535 && (e -= 65536, n += L(e >>> 10 & 1023 | 55296), e = 56320 | 1023 & e), n += L(e) }).join("") } function a(e) { return 10 > e - 48 ? e - 22 : 26 > e - 65 ? e - 65 : 26 > e - 97 ? e - 97 : k } function p(e, n) { return e + 22 + 75 * (26 > e) - ((0 != n) << 5) } function c(e, n, f) { var o = 0; for (e = f ? K(e / B) : e >> 1, e += K(e / n); e > J * z >> 1; o += k) e = K(e / J); return K(o + (J + 1) * e / (e + A)) } function y(e) { var n, f, o, d, t, l, s, p, y, m, r = [], v = e.length, w = 0, b = D, g = C; for (f = e.lastIndexOf(E), 0 > f && (f = 0), o = 0; f > o; ++o) e.charCodeAt(o) >= 128 && i("not-basic"), r.push(e.charCodeAt(o)); for (d = f > 0 ? f + 1 : 0; v > d;) { for (t = w, l = 1, s = k; d >= v && i("invalid-input"), p = a(e.charCodeAt(d++)), (p >= k || p > K((j - w) / l)) && i("overflow"), w += p * l, y = g >= s ? q : s >= g + z ? z : s - g, !(y > p); s += k) m = k - y, l > K(j / m) && i("overflow"), l *= m; n = r.length + 1, g = c(w - t, n, 0 == t), K(w / n) > j - b && i("overflow"), b += K(w / n), w %= n, r.splice(w++, 0, b) } return u(r) } function m(e) { var n, f, o, d, t, l, u, a, y, m, r, v, w, b, g, h = []; for (e = s(e), v = e.length, n = D, f = 0, t = C, l = 0; v > l; ++l) r = e[l], 128 > r && h.push(L(r)); for (o = d = h.length, d && h.push(E); v > o;) { for (u = j, l = 0; v > l; ++l) r = e[l], r >= n && u > r && (u = r); for (w = o + 1, u - n > K((j - f) / w) && i("overflow"), f += (u - n) * w, n = u, l = 0; v > l; ++l) if (r = e[l], n > r && ++f > j && i("overflow"), r == n) { for (a = f, y = k; m = t >= y ? q : y >= t + z ? z : y - t, !(m > a); y += k) g = a - m, b = k - m, h.push(L(p(m + g % b, 0))), a = K(g / b); h.push(L(p(a, 0))), t = c(f, w, o == d), f = 0, ++o } ++f, ++n } return h.join("") } function r(e) { return l(e, function (e) { return F.test(e) ? y(e.slice(4).toLowerCase()) : e }) } function v(e) { return l(e, function (e) { return G.test(e) ? "xn--" + m(e) : e }) } var w = "object" == typeof o && o, b = "object" == typeof f && f && f.exports == w && f, g = "object" == typeof n && n; (g.global === g || g.window === g) && (d = g); var h, x, j = 2147483647, k = 36, q = 1, z = 26, A = 38, B = 700, C = 72, D = 128, E = "-", F = /^xn--/, G = /[^ -~]/, H = /\\x2E|\\u3002|\\uFF0E|\\uFF61/g, I = { overflow: "Overflow: input needs wider integers to process", "not-basic": "Illegal input >= 0x80 (not a basic code point)", "invalid-input": "Invalid input" }, J = k - q, K = Math.floor, L = String.fromCharCode; if (h = { version: "1.2.4", ucs2: {decode: s, encode: u}, decode: y, encode: m, toASCII: v, toUnicode: r }, "function" == typeof e && "object" == typeof e.amd && e.amd) e("punycode", function () { return h }); else if (w && !w.nodeType) if (b) b.exports = h; else for (x in h) h.hasOwnProperty(x) && (w[x] = h[x]); else d.punycode = h }(this) }).call(this, "undefined" != typeof global ? global : "undefined" != typeof self ? self : "undefined" != typeof window ? window : {}) }, {}], 2: [function (e, n) { function f(e, n, f) { !e.defaultView || n === e.defaultView.pageXOffset && f === e.defaultView.pageYOffset || e.defaultView.scrollTo(n, f) } function o(e, n) { try { n && (n.width = e.width, n.height = e.height, n.getContext("2d").putImageData(e.getContext("2d").getImageData(0, 0, e.width, e.height), 0, 0)) } catch (f) { t("Unable to copy canvas content from", e, f) } } function d(e, n) { for (var f = 3 === e.nodeType ? document.createTextNode(e.nodeValue) : e.cloneNode(!1), i = e.firstChild; i;) (n === !0 || 1 !== i.nodeType || "SCRIPT" !== i.nodeName) && f.appendChild(d(i, n)), i = i.nextSibling; return 1 === e.nodeType && (f._scrollTop = e.scrollTop, f._scrollLeft = e.scrollLeft, "CANVAS" === e.nodeName ? o(e, f) : ("TEXTAREA" === e.nodeName || "SELECT" === e.nodeName) && (f.value = e.value)), f } function i(e) { if (1 === e.nodeType) { e.scrollTop = e._scrollTop, e.scrollLeft = e._scrollLeft; for (var n = e.firstChild; n;) i(n), n = n.nextSibling } } var t = e("./log"); n.exports = function (e, n, o, t, l, s, u) { var a = d(e.documentElement, l.javascriptEnabled), p = n.createElement("iframe"); return p.className = "html2canvas-container", p.style.visibility = "hidden", p.style.position = "fixed", p.style.left = "-10000px", p.style.top = "0px", p.style.border = "0", p.width = o, p.height = t, p.scrolling = "no", n.body.appendChild(p), new Promise(function (n) { var o = p.contentWindow.document; p.contentWindow.onload = p.onload = function () { var e = setInterval(function () { o.body.childNodes.length > 0 && (i(o.documentElement), clearInterval(e), "view" === l.type && (p.contentWindow.scrollTo(s, u), !/(iPad|iPhone|iPod)/g.test(navigator.userAgent) || p.contentWindow.scrollY === u && p.contentWindow.scrollX === s || (o.documentElement.style.top = -u + "px", o.documentElement.style.left = -s + "px", o.documentElement.style.position = "absolute")), n(p)) }, 50) }, o.open(), o.write("<!DOCTYPE html><html></html>"), f(e, s, u), o.replaceChild(o.adoptNode(a), o.documentElement), o.close() }) } }, {"./log": 13}], 3: [function (e, n) { function f(e) { this.r = 0, this.g = 0, this.b = 0, this.a = null; this.fromArray(e) || this.namedColor(e) || this.rgb(e) || this.rgba(e) || this.hex6(e) || this.hex3(e) } f.prototype.darken = function (e) { var n = 1 - e; return new f([Math.round(this.r * n), Math.round(this.g * n), Math.round(this.b * n), this.a]) }, f.prototype.isTransparent = function () { return 0 === this.a }, f.prototype.isBlack = function () { return 0 === this.r && 0 === this.g && 0 === this.b }, f.prototype.fromArray = function (e) { return Array.isArray(e) && (this.r = Math.min(e[0], 255), this.g = Math.min(e[1], 255), this.b = Math.min(e[2], 255), e.length > 3 && (this.a = e[3])), Array.isArray(e) }; var o = /^#([a-f0-9]{3})$/i; f.prototype.hex3 = function (e) { var n = null; return null !== (n = e.match(o)) && (this.r = parseInt(n[1][0] + n[1][0], 16), this.g = parseInt(n[1][1] + n[1][1], 16), this.b = parseInt(n[1][2] + n[1][2], 16)), null !== n }; var d = /^#([a-f0-9]{6})$/i; f.prototype.hex6 = function (e) { var n = null; return null !== (n = e.match(d)) && (this.r = parseInt(n[1].substring(0, 2), 16), this.g = parseInt(n[1].substring(2, 4), 16), this.b = parseInt(n[1].substring(4, 6), 16)), null !== n }; var i = /^rgb\\(\\s*(\\d{1,3})\\s*,\\s*(\\d{1,3})\\s*,\\s*(\\d{1,3})\\s*\\)$/; f.prototype.rgb = function (e) { var n = null; return null !== (n = e.match(i)) && (this.r = Number(n[1]), this.g = Number(n[2]), this.b = Number(n[3])), null !== n }; var t = /^rgba\\(\\s*(\\d{1,3})\\s*,\\s*(\\d{1,3})\\s*,\\s*(\\d{1,3})\\s*,\\s*(\\d?\\.?\\d+)\\s*\\)$/; f.prototype.rgba = function (e) { var n = null; return null !== (n = e.match(t)) && (this.r = Number(n[1]), this.g = Number(n[2]), this.b = Number(n[3]), this.a = Number(n[4])), null !== n }, f.prototype.toString = function () { return null !== this.a && 1 !== this.a ? "rgba(" + [this.r, this.g, this.b, this.a].join(",") + ")" : "rgb(" + [this.r, this.g, this.b].join(",") + ")" }, f.prototype.namedColor = function (e) { e = e.toLowerCase(); var n = l[e]; if (n) this.r = n[0], this.g = n[1], this.b = n[2]; else if ("transparent" === e) return this.r = this.g = this.b = this.a = 0, !0; return !!n }, f.prototype.isColor = !0; var l = { aliceblue: [240, 248, 255], antiquewhite: [250, 235, 215], aqua: [0, 255, 255], aquamarine: [127, 255, 212], azure: [240, 255, 255], beige: [245, 245, 220], bisque: [255, 228, 196], black: [0, 0, 0], blanchedalmond: [255, 235, 205], blue: [0, 0, 255], blueviolet: [138, 43, 226], brown: [165, 42, 42], burlywood: [222, 184, 135], cadetblue: [95, 158, 160], chartreuse: [127, 255, 0], chocolate: [210, 105, 30], coral: [255, 127, 80], cornflowerblue: [100, 149, 237], cornsilk: [255, 248, 220], crimson: [220, 20, 60], cyan: [0, 255, 255], darkblue: [0, 0, 139], darkcyan: [0, 139, 139], darkgoldenrod: [184, 134, 11], darkgray: [169, 169, 169], darkgreen: [0, 100, 0], darkgrey: [169, 169, 169], darkkhaki: [189, 183, 107], darkmagenta: [139, 0, 139], darkolivegreen: [85, 107, 47], darkorange: [255, 140, 0], darkorchid: [153, 50, 204], darkred: [139, 0, 0], darksalmon: [233, 150, 122], darkseagreen: [143, 188, 143], darkslateblue: [72, 61, 139], darkslategray: [47, 79, 79], darkslategrey: [47, 79, 79], darkturquoise: [0, 206, 209], darkviolet: [148, 0, 211], deeppink: [255, 20, 147], deepskyblue: [0, 191, 255], dimgray: [105, 105, 105], dimgrey: [105, 105, 105], dodgerblue: [30, 144, 255], firebrick: [178, 34, 34], floralwhite: [255, 250, 240], forestgreen: [34, 139, 34], fuchsia: [255, 0, 255], gainsboro: [220, 220, 220], ghostwhite: [248, 248, 255], gold: [255, 215, 0], goldenrod: [218, 165, 32], gray: [128, 128, 128], green: [0, 128, 0], greenyellow: [173, 255, 47], grey: [128, 128, 128], honeydew: [240, 255, 240], hotpink: [255, 105, 180], indianred: [205, 92, 92], indigo: [75, 0, 130], ivory: [255, 255, 240], khaki: [240, 230, 140], lavender: [230, 230, 250], lavenderblush: [255, 240, 245], lawngreen: [124, 252, 0], lemonchiffon: [255, 250, 205], lightblue: [173, 216, 230], lightcoral: [240, 128, 128], lightcyan: [224, 255, 255], lightgoldenrodyellow: [250, 250, 210], lightgray: [211, 211, 211], lightgreen: [144, 238, 144], lightgrey: [211, 211, 211], lightpink: [255, 182, 193], lightsalmon: [255, 160, 122], lightseagreen: [32, 178, 170], lightskyblue: [135, 206, 250], lightslategray: [119, 136, 153], lightslategrey: [119, 136, 153], lightsteelblue: [176, 196, 222], lightyellow: [255, 255, 224], lime: [0, 255, 0], limegreen: [50, 205, 50], linen: [250, 240, 230], magenta: [255, 0, 255], maroon: [128, 0, 0], mediumaquamarine: [102, 205, 170], mediumblue: [0, 0, 205], mediumorchid: [186, 85, 211], mediumpurple: [147, 112, 219], mediumseagreen: [60, 179, 113], mediumslateblue: [123, 104, 238], mediumspringgreen: [0, 250, 154], mediumturquoise: [72, 209, 204], mediumvioletred: [199, 21, 133], midnightblue: [25, 25, 112], mintcream: [245, 255, 250], mistyrose: [255, 228, 225], moccasin: [255, 228, 181], navajowhite: [255, 222, 173], navy: [0, 0, 128], oldlace: [253, 245, 230], olive: [128, 128, 0], olivedrab: [107, 142, 35], orange: [255, 165, 0], orangered: [255, 69, 0], orchid: [218, 112, 214], palegoldenrod: [238, 232, 170], palegreen: [152, 251, 152], paleturquoise: [175, 238, 238], palevioletred: [219, 112, 147], papayawhip: [255, 239, 213], peachpuff: [255, 218, 185], peru: [205, 133, 63], pink: [255, 192, 203], plum: [221, 160, 221], powderblue: [176, 224, 230], purple: [128, 0, 128], rebeccapurple: [102, 51, 153], red: [255, 0, 0], rosybrown: [188, 143, 143], royalblue: [65, 105, 225], saddlebrown: [139, 69, 19], salmon: [250, 128, 114], sandybrown: [244, 164, 96], seagreen: [46, 139, 87], seashell: [255, 245, 238], sienna: [160, 82, 45], silver: [192, 192, 192], skyblue: [135, 206, 235], slateblue: [106, 90, 205], slategray: [112, 128, 144], slategrey: [112, 128, 144], snow: [255, 250, 250], springgreen: [0, 255, 127], steelblue: [70, 130, 180], tan: [210, 180, 140], teal: [0, 128, 128], thistle: [216, 191, 216], tomato: [255, 99, 71], turquoise: [64, 224, 208], violet: [238, 130, 238], wheat: [245, 222, 179], white: [255, 255, 255], whitesmoke: [245, 245, 245], yellow: [255, 255, 0], yellowgreen: [154, 205, 50] }; n.exports = f }, {}], 4: [function (n, f) { function o(e, n) { var f = j++; if (n = n || {}, n.logging && (v.options.logging = !0, v.options.start = Date.now()), n.async = "undefined" == typeof n.async ? !0 : n.async, n.allowTaint = "undefined" == typeof n.allowTaint ? !1 : n.allowTaint, n.removeContainer = "undefined" == typeof n.removeContainer ? !0 : n.removeContainer, n.javascriptEnabled = "undefined" == typeof n.javascriptEnabled ? !1 : n.javascriptEnabled, n.imageTimeout = "undefined" == typeof n.imageTimeout ? 1e4 : n.imageTimeout, n.renderer = "function" == typeof n.renderer ? n.renderer : c, n.strict = !!n.strict, "string" == typeof e) { if ("string" != typeof n.proxy) return Promise.reject("Proxy must be used when rendering url"); var o = null != n.width ? n.width : window.innerWidth, t = null != n.height ? n.height : window.innerHeight; return g(a(e), n.proxy, document, o, t, n).then(function (e) { return i(e.contentWindow.document.documentElement, e, n, o, t) }) } var l = (void 0 === e ? [document.documentElement] : e.length ? e : [e])[0]; return l.setAttribute(x + f, f), d(l.ownerDocument, n, l.ownerDocument.defaultView.innerWidth, l.ownerDocument.defaultView.innerHeight, f).then(function (e) { return "function" == typeof n.onrendered && (v("options.onrendered is deprecated, html2canvas returns a Promise containing the canvas"), n.onrendered(e)), e }) } function d(e, n, f, o, d) { return b(e, e, f, o, n, e.defaultView.pageXOffset, e.defaultView.pageYOffset).then(function (t) { v("Document cloned"); var l = x + d, s = "[" + l + "=\'" + d + "\']"; e.querySelector(s).removeAttribute(l); var u = t.contentWindow, a = u.document.querySelector(s), p = Promise.resolve("function" == typeof n.onclone ? n.onclone(u.document) : !0); return p.then(function () { return i(a, t, n, f, o) }) }) } function i(e, n, f, o, d) { var i = n.contentWindow, a = new p(i.document), c = new y(f, a), r = h(e), w = "view" === f.type ? o : s(i.document), b = "view" === f.type ? d : u(i.document), g = new f.renderer(w, b, c, f, document), x = new m(e, g, a, c, f); return x.ready.then(function () { v("Finished rendering"); var o; return o = "view" === f.type ? l(g.canvas, { width: g.canvas.width, height: g.canvas.height, top: 0, left: 0, x: 0, y: 0 }) : e === i.document.body || e === i.document.documentElement || null != f.canvas ? g.canvas : l(g.canvas, { width: null != f.width ? f.width : r.width, height: null != f.height ? f.height : r.height, top: r.top, left: r.left, x: 0, y: 0 }), t(n, f), o }) } function t(e, n) { n.removeContainer && (e.parentNode.removeChild(e), v("Cleaned up container")) } function l(e, n) { var f = document.createElement("canvas"), o = Math.min(e.width - 1, Math.max(0, n.left)), d = Math.min(e.width, Math.max(1, n.left + n.width)), i = Math.min(e.height - 1, Math.max(0, n.top)), t = Math.min(e.height, Math.max(1, n.top + n.height)); f.width = n.width, f.height = n.height; var l = d - o, s = t - i; return v("Cropping canvas at:", "left:", n.left, "top:", n.top, "width:", l, "height:", s), v("Resulting crop with width", n.width, "and height", n.height, "with x", o, "and y", i), f.getContext("2d").drawImage(e, o, i, l, s, n.x, n.y, l, s), f } function s(e) { return Math.max(Math.max(e.body.scrollWidth, e.documentElement.scrollWidth), Math.max(e.body.offsetWidth, e.documentElement.offsetWidth), Math.max(e.body.clientWidth, e.documentElement.clientWidth)) } function u(e) { return Math.max(Math.max(e.body.scrollHeight, e.documentElement.scrollHeight), Math.max(e.body.offsetHeight, e.documentElement.offsetHeight), Math.max(e.body.clientHeight, e.documentElement.clientHeight)) } function a(e) { var n = document.createElement("a"); return n.href = e, n.href = n.href, n } var p = n("./support"), c = n("./renderers/canvas"), y = n("./imageloader"), m = n("./nodeparser"), r = n("./nodecontainer"), v = n("./log"), w = n("./utils"), b = n("./clone"), g = n("./proxy").loadUrlDocument, h = w.getBounds, x = "data-html2canvas-node", j = 0; o.CanvasRenderer = c, o.NodeContainer = r, o.log = v, o.utils = w; var k = "undefined" == typeof document || "function" != typeof Object.create || "function" != typeof document.createElement("canvas").getContext ? function () { return Promise.reject("No canvas support") } : o; f.exports = k, "function" == typeof e && e.amd && e("html2canvas", [], function () { return k }) }, { "./clone": 2, "./imageloader": 11, "./log": 13, "./nodecontainer": 14, "./nodeparser": 15, "./proxy": 16, "./renderers/canvas": 20, "./support": 22, "./utils": 26 }], 5: [function (e, n) { function f(e) { if (this.src = e, o("DummyImageContainer for", e), !this.promise || !this.image) { o("Initiating DummyImageContainer"), f.prototype.image = new Image; var n = this.image; f.prototype.promise = new Promise(function (e, f) { n.onload = e, n.onerror = f, n.src = d(), n.complete === !0 && e(n) }) } } var o = e("./log"), d = e("./utils").smallImage; n.exports = f }, {"./log": 13, "./utils": 26}], 6: [function (e, n) { function f(e, n) { var f, d, i = document.createElement("div"), t = document.createElement("img"), l = document.createElement("span"), s = "Hidden Text"; i.style.visibility = "hidden", i.style.fontFamily = e, i.style.fontSize = n, i.style.margin = 0, i.style.padding = 0, document.body.appendChild(i), t.src = o(), t.width = 1, t.height = 1, t.style.margin = 0, t.style.padding = 0, t.style.verticalAlign = "baseline", l.style.fontFamily = e, l.style.fontSize = n, l.style.margin = 0, l.style.padding = 0, l.appendChild(document.createTextNode(s)), i.appendChild(l), i.appendChild(t), f = t.offsetTop - l.offsetTop + 1, i.removeChild(l), i.appendChild(document.createTextNode(s)), i.style.lineHeight = "normal", t.style.verticalAlign = "super", d = t.offsetTop - i.offsetTop + 1, document.body.removeChild(i), this.baseline = f, this.lineWidth = 1, this.middle = d } var o = e("./utils").smallImage; n.exports = f }, {"./utils": 26}], 7: [function (e, n) { function f() { this.data = {} } var o = e("./font"); f.prototype.getMetrics = function (e, n) { return void 0 === this.data[e + "-" + n] && (this.data[e + "-" + n] = new o(e, n)), this.data[e + "-" + n] }, n.exports = f }, {"./font": 6}], 8: [function (e, n) { function f(n, f, o) { this.image = null, this.src = n; var i = this, t = d(n); this.promise = (f ? new Promise(function (e) { "about:blank" === n.contentWindow.document.URL || null == n.contentWindow.document.documentElement ? n.contentWindow.onload = n.onload = function () { e(n) } : e(n) }) : this.proxyLoad(o.proxy, t, o)).then(function (n) { var f = e("./core"); returnangularJS使用ocLazyLoad实现js延迟加载