├── img ├── Stone.png ├── Spectre.jpg ├── weaver.jpg ├── Dark Seer.jpg ├── Venomancer.jpg ├── Beast Master.jpg ├── Doom Bringer.jpg ├── Dragon Knight.jpg └── Ancient Apparition.jpg ├── .gitignore ├── README.md ├── index.html └── js └── html2canvas.js /img/Stone.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cosyer/html2PDF/HEAD/img/Stone.png -------------------------------------------------------------------------------- /img/Spectre.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cosyer/html2PDF/HEAD/img/Spectre.jpg -------------------------------------------------------------------------------- /img/weaver.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cosyer/html2PDF/HEAD/img/weaver.jpg -------------------------------------------------------------------------------- /img/Dark Seer.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cosyer/html2PDF/HEAD/img/Dark Seer.jpg -------------------------------------------------------------------------------- /img/Venomancer.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cosyer/html2PDF/HEAD/img/Venomancer.jpg -------------------------------------------------------------------------------- /img/Beast Master.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cosyer/html2PDF/HEAD/img/Beast Master.jpg -------------------------------------------------------------------------------- /img/Doom Bringer.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cosyer/html2PDF/HEAD/img/Doom Bringer.jpg -------------------------------------------------------------------------------- /img/Dragon Knight.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cosyer/html2PDF/HEAD/img/Dragon Knight.jpg -------------------------------------------------------------------------------- /img/Ancient Apparition.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cosyer/html2PDF/HEAD/img/Ancient Apparition.jpg -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | Thumbs.db 3 | db.json 4 | *.log 5 | node_modules/ 6 | public/ 7 | .deploy*/ 8 | .idea 9 | yarn.lock 10 | package-lock.json 11 | debug.log -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # html转成pdf下载(html2canvas 和 jsPDF) 2 | 3 | ## html2canvas 4 | 5 | ### 简介 6 | 7 | 我们可以直接在浏览器端使用html2canvas,对整个或局部页面(一般为body)进行截图。但这并不是真的截图,而是通过遍历页面DOM结构,收集所有元素信息及相应样式,渲染出canvas image。 8 | 9 | 由于html2canvas只能将它能处理的生成canvas image,因此渲染出来的结果并不是100%与原来一致。但它不需要服务器参与,整个图片都由客户端浏览器生成,使用很方便。 10 | 11 | ### 使用 12 | 13 | 使用的API也很简洁,下面代码可以将某个元素渲染成canvas: 14 | 15 | ```javascript 16 | html2canvas(element, { 17 | onrendered: function(canvas) { 18 | // canvas is the final rendered element 19 | } 20 | }); 21 | ``` 22 | 23 | ## jsPDF 24 | 25 | jsPDF库可以用于浏览器端生成PDF。 26 | 27 | ### 文字生成PDF 28 | 29 | 使用方法如下: 30 | 31 | ```javascript 32 | // 默认a4大小,竖直方向,mm单位的PDF 33 | var doc = new jsPDF(); 34 | 35 | // 添加文本‘Hello World’ 36 | doc.text('Hello World', 10, 10); 37 | doc.save('a4.pdf'); 38 | ``` 39 | 40 | ### 图片生成PDF 41 | 42 | 使用方法如下: 43 | 44 | ```javascript 45 | // 三个参数,第一个方向,第二个单位,第三个尺寸格式 46 | var doc = new jsPDF('landscape','pt',[205, 115]) 47 | 48 | // 将图片转化为dataUrl 49 | var imageData = 'data:image/png;base64,...'; 50 | 51 | doc.addImage(imageData, 'PNG', 0, 0, 205, 115); 52 | doc.save('a4.pdf'); 53 | ``` 54 | 55 | ### 文字与图片生成PDF 56 | 57 | ```javascript 58 | // 三个参数,第一个方向,第二个尺寸,第三个尺寸格式 59 | var doc = new jsPDF('landscape','pt',[205, 155]) 60 | 61 | // 将图片转化为dataUrl 62 | var imageData = ‘data:image/png;base64,iVBORw0KGgo...’; 63 | 64 | //设置字体大小 65 | doc.setFontSize(20); 66 | 67 | //10,20这两参数控制文字距离左边,与上边的距离 68 | doc.text('Stone', 10, 20); 69 | 70 | // 0, 40, 控制文字距离左边,与上边的距离 71 | doc.addImage(imageData, 'PNG', 0, 40, 205, 115); 72 | doc.save('a4.pdf') 73 | ``` 74 | 75 | ### 多页的处理 76 | 可参考 https://www.cnblogs.com/yizhilin/p/8603879.html 77 | 78 | - 去除body`overflow:hidden`, 79 | 80 | - 设置html2canvas允许跨域:allowTaint: true 81 | 82 | - 设置高度:height: $("#xxx").outerHeight() -------------------------------------------------------------------------------- /index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | html2canvas example 5 | 6 | 51 | 52 | 53 |
54 | 62 |
63 |
64 | 69 |
70 | 71 | 72 |

Stone Giant

73 |

74 | Coming to life as a chunk of stone, Tiny's origins are a mystery on 75 | which he continually speculates. He is a Stone Giant now, but what did 76 | he used to be? A splinter broken from a Golem's heel? A shard swept 77 | from a gargoyle-sculptor's workshop? A fragment of the Oracular Visage 78 | of Garthos? A deep curiosity drives him, and he travels the world 79 | tirelessly seeking his origins, his parentage, his people. As he 80 | roams, he gathers weight and size; the forces that weather lesser 81 | rocks, instead cause Tiny to grow and ever grow. 82 |

83 |

84 | 以一团石头的形式出现的生命体,小小不断思索他的起源,但这始终是个谜。现在的他是个石巨人,但过去是什么呢?从土傀儡的脚后跟掉落的碎片?从制造石像鬼的工房被打扫出来的碎屑?神圣预言石的表层之砂?受到强烈的好奇心驱使,他不知疲倦的环游世界,寻找着他的起源,他的出身,和他的种族。在旅途中,他变得越来越庞大,不过路上的风雨吹打掉了他身上的石头,所以他不停的吸收新的岩石,永远在长大。 85 |

86 | 87 |

Spectre

88 |

89 | Just as higher states of energy seek a lower level, the Spectre known 90 | as Mercurial is a being of intense and violent energy who finds 91 | herself irresistibly drawn to scenes of strife as they unfold in the 92 | physical world. While her normal spectral state transcends sensory 93 | limitations, each time she takes on a physical manifestation, she is 94 | stricken by a loss of self--though not of purpose. In the clash of 95 | combat, her identity shatters and reconfigures, and she begins to 96 | regain awareness. She grasps that she is Mercurial the Spectre--and 97 | that all of her Haunts are but shadows of the one true Spectre. Focus 98 | comes in the struggle for survival; her true mind reasserts itself; 99 | until in the final moments of victory or defeat, she transcends matter 100 | and is restored once more to her eternal form. 101 |

102 |

103 | 和所有强大的能量都喜欢欺凌弱小一样,被称为墨丘利的幽鬼也是一个拥有着强横能量的存在,同样的,她对现实世界中的冲突和纷争无比着迷。然而她平时的幽鬼形态超越了常人的感知范围,因此每当她以实体形态出现时,她不得不损失一部分自我能量——尽管她也不愿意。在战斗中,她的自我意识逐渐散落并重新聚合,她也开始有了意识。她意识到了自己是幽鬼墨丘利——其他所有的鬼影都只是她自我的阴影。出于重新凝聚的打算,她开始专注,她的心智也在不断的成熟。只有等到她取得胜利或者彻底失败时,她那超物质的形态才会得以重聚。 104 |

105 | 106 |

Ancient Apparition

107 |

108 | Kaldr, the Ancient Apparition, is an image projected from outside 109 | time. He springs from the cold, infinite void that both predates the 110 | universe and awaits its end. Kaldr is, Kaldr was, Kaldr shall be...and 111 | what we perceive, powerful as it appears to us, is but the faintest 112 | faded echo of the true, eternal Kaldr. Some believe that as the cosmos 113 | ages and approaches its final moments, the brightness and power of 114 | Kaldr will also intensify--that the Ancient Apparition will grow 115 | younger and stronger as eternity's end draws nigh. His grip of ice 116 | will bring all matter to a stop, his image will cast a light too 117 | terrible to behold. An Apparition no longer! 118 |

119 |

120 | 卡德尔,极寒幽魂,是时光之外的冰冷投影。他来自寒冷的无尽虚空,目睹宇宙诞生,见证宇宙终结。卡德尔是夕在,今在,永在的无上力量...我们的所有认知,所有自认为正确的强大的事物,在永恒的卡德尔看来,不过是最细微最无力的附和。有人相信,随着宇宙的老化并走向衰亡,卡德尔的力量和光芒也将变得更强——极寒幽魂将更加年轻,更加强大。他对冰霜的控制能够冻结一切事物,他的投影放出的光芒异常夺目。他将不再是幽魂,而是神! 121 |

122 | 123 |

Weaver

124 |

125 | The fabric of creation needs constant care, lest it grow tattered; for 126 | when it unravels, whole worlds come undone. It is the work of the 127 | Weavers to keep the fabric tight, to repair worn spots in the mesh of 128 | reality. They also defend from the things that gnaw and lay their eggs 129 | in frayed regions, whose young can quickly devour an entire universe 130 | if the Weavers let their attention lapse. Skitskurr was a master 131 | Weaver, charged with keep one small patch of creation tightly woven 132 | and unfaded. But the job was not enough to satisfy. It nagged him that 133 | the original work of creation all lay in the past; the Loom had done 134 | its work and travelled on. He wanted to create rather than merely 135 | maintain--to weave worlds of his own devising. He began making small 136 | changes to his domain, but the thrill of creation proved addictive, 137 | and his strokes became bolder, pulling against the pattern that the 138 | Loom had woven. The guardians came, with their scissors, and Weaver's 139 | world was pared off, snipped from the cosmic tapestry, which they 140 | rewove without him in it. Skitskurr found himself alone, apart from 141 | his kind, a state that would have been torment for any other Weaver. 142 | But Skitskurr rejoiced, for now he was free. Free to create for 143 | himself, to begin anew. The raw materials he needed to weave a new 144 | reality were all around him. All he had to do was tear apart this old 145 | world at the seams. 146 |

147 |

148 | 创世之纱需要长期细心的照料,以防止其变得残破;因为一旦它散开了,整个世界就将毁于一旦。编织者的工作就是保持创世之纱的紧密,用现实之网修补它的破损。他们同样要防止那些在创世之纱的缺口上产卵或者侵蚀创世之纱的虫子,只要编织者稍微分心,这些家伙的幼虫就能吞噬掉整个宇宙。斯吉茨格尔是一名大师级的编织者,负责维护一块小补丁的紧密。然而这项任务并不能满足他,他经常唠叨过去那些原始的创造工作,对干完活就走人的世界纺织者也是颇有微词。他想创造,不想只是维护——他想按自己的设计编织出自己的世界。他开始在他负责的区域上做手脚,逐渐不能自拔,他的胆子也愈发的大,甚至私自改动了世界纺织者编织的图案。最后,守卫者来了,毁掉了编织者所作的一切,直接从创世之纱上去除了这一块,然后重新编织,却不让他参与其中。斯吉茨格尔现在孤身一人,被种群所弃,换做任何其他编织者,都会备受折磨。然而斯吉茨格尔却无比愉悦,因为他终于自由了,能够自由的创造,重头开始。他创造新世界所需的所有材料都触手可及。他只需要从缺口处将现在的世界撕裂。 149 |

150 | 151 |

Doom Bringer

152 |

153 | A towering being of unimaginable evil, Lucifer the Doom Bringer 154 | marches the farthest reaches of the world in search of new and 155 | exciting ways to satisfy his taste for unrest and greed. Once a feared 156 | leader in the army of the Purgers of the Realm, Doom left his position 157 | as a comrade of fellow demonic warriors as he simply could not bear 158 | the thought of sharing the glory of pillaging and feats of destruction 159 | with other lowly demons. Despite no longer leading an army, Doom is a 160 | fearful foe in combat, possessing mastery of hellish magic and 161 | physical attacks - eventually, the world will belong to Doom. 162 |

163 |

164 | 一个邪恶程度超乎想象的存在——末日使者路西法在世界各地不停寻找着新的方法来满足他的贪婪和对骚乱的热衷。他曾经是其所在国度中备受畏惧的灭劫军团统帅,然而末日使者后来却离开了他的将军职位,丢下了一帮恶魔战士,原因很简单,他无法与一帮低级恶魔分享掠夺和毁灭带来的所谓荣耀。尽管他不再是军队的统帅了,末日使者在战斗中仍然是个令人恐惧的对手,他拥有极高的肉搏技巧,还掌握了邪恶的地狱魔法——最终,整个世界将为他所有。 165 |

166 | 167 |

Dragon Knight

168 |

169 | After years on the trail of a legendary Eldwurm, the Knight Davion 170 | found himself facing a disappointing foe: the dreaded Slyrak had grown 171 | ancient and frail, its wings tattered, its few remaining scales 172 | stricken with scale-rot, its fangs ground to nubs, and its fire-gouts 173 | no more threatening than a pack of wet matchsticks. Seeing no honor to 174 | be gained in dragon-murder, Knight Davion prepared to turn away and 175 | leave his old foe to die in peace. But a voice crept into his 176 | thoughts, and Slyrak gave a whispered plea that Davion might honor him 177 | with death in combat. Davion agreed, and found himself rewarded beyond 178 | expectation for his act of mercy: As he sank his blade in Slyrak's 179 | breast, the dragon pierced Davion's throat with a talon. As their 180 | blood mingled, Slyrak sent his power out along the Blood Route, 181 | sending all its strength and centuries of wisdom to the knight. The 182 | dragon's death sealed their bond and Dragon Knight was born. The 183 | ancient power slumbers in the Dragon Knight Davion, waking when he 184 | calls it. Or perhaps it is the Dragon that calls the Knight... 185 |

186 |

187 | 在传说中的龙冢——厄尔多姆试炼多年以后,骑士戴维安发现自己的对手愈发不能令他满意了:过去那个让人闻风丧胆的神龙斯莱瑞克已经变得苍老而脆弱,它的双翼已经残破,它所剩不多的龙鳞也开始腐烂,它的爪子变得肿大老化,它曾经引以为傲的火焰吐息现在威力和进水了的火柴差不多。戴维安觉得这样的屠龙行径已经不能给他带来任何荣誉,转身就要离开,让他的老对手安静的死去。但是他的脑海里传来了一个声音,斯莱瑞克低声的乞求着,让戴维安允许它光荣的战死。戴维安同意了,随即发现他的怜悯给他带来了意外的收获:当他将手中的锋刃刺入斯莱瑞克的胸膛时,龙使出最后的力量用龙爪刺穿了他的喉咙,随着他们血液的融合,斯莱瑞克将它所有的力量随着血液赐予了戴维安,也赐予了他龙族千万年来的智慧。龙的死去将他们的命运完全的绑定在了一起,龙骑士横空出世。古老的力量在龙骑士戴维安的身体里沉睡着,当他需要力量时则完全复苏。而龙族之力,也唤醒了骑士的所有力量... 188 |

189 | 190 |

Venomancer

191 |

192 | In the Acid Jungles of Jidi Isle, poison runs in the veins and bubbles 193 | in the guts of every creature that scuttles, climbs or swoops between 194 | fluorescent vines dripping with caustic sap. Yet even in this toxic 195 | menagerie, Venomancer is acknowledged as the most venomous. Ages ago, 196 | an Herbalist named Lesale crossed the Bay of Fradj by coracle, 197 | searching for potent essences that might be extracted from bark and 198 | root, and found instead a nightmare transformation. Two leagues into 199 | Jidi's jungle, Lesale encountered a reptile camouflaged as an 200 | epiphyte, which stung him as he mistakenly plucked it. In desperation, 201 | he used his partial knowledge of the jungle's herbal bounty, mixing 202 | the venom of the (swiftly throttled) reptile with the nectar of an 203 | armored orchid, to compound an antidote. In the moments before a black 204 | paralysis claimed him completely, he injected himself by orchid-thorn, 205 | and instantly fell into a coma. Seventeen years later, something 206 | stirred in the spot where he had fallen, throwing off the years' 207 | accumulation of humus: Venomancer. Lesale the Herbalist no longer--but 208 | Lesale the Deathbringer. His mind was all but erased, and his flesh 209 | had been consumed and replaced by a new type of matter--one fusing the 210 | venom of the reptile with the poisonous integument of the orchid. 211 | Jidi's Acid Jungles knew a new master, one before whom even the most 212 | vicious predators soon learned to bow or burrow for their lives. The 213 | lurid isle proved too confining, and some human hunger deep in the 214 | heart of the Venomancer drove Lesale out in search of new poisons--and 215 | new deaths to bring. 216 |

217 |

218 | 在基迪岛上的浓酸密林中,在所有生物的体内,包括植物的根茎,动物的内脏中,都流淌着致命的腐蚀剧毒。然而,就算在这种毒巢里,剧毒术士也是公认的万毒之王。多年以前,一个叫做里瑟尔的植物学家乘坐小舟跨越弗拉基海湾,想要从植物的根须中提取出一种强力药剂,结果他却遭遇了噩梦一般的变故。在深入到基迪岛密林中数英里时,里瑟尔遇到了一种伪装成寄生植物的毒性爬虫,当他想把爬虫扯下来的时候,被爬虫狠狠的蛰了。绝望之际,他用他对丛林植物仅有的认知,飞快地掐住这只爬虫后,将它的毒液和一种带甲兰花的花蜜混合,合成了解毒剂。他用兰花的尖刺为自己注射了解毒剂,然后立即陷入昏迷,并且逐渐陷入了全身完全麻木的状态。十七年后,在他倒下的地方,从多年积累的腐土中钻出某个东西:剧毒术士。草药学家里瑟尔已经不复存在,现在他是死亡使者里瑟尔。他的记忆几乎都没有了,他原来的肉体已经毁灭,现在被一种新的物质所替代--融合了那只爬虫的毒液和兰花的毒性外皮。基迪岛的浓酸丛林现在有了新的主人,过去最剧毒的捕食者在他面前都只能逃走或臣服求饶。这个可怕的岛屿毕竟太有限了,里瑟尔受到内心深处残留的人类的饥渴驱使,离开了岛屿,去寻找新的毒物,以及带来新的死亡。 219 |

220 | 221 |

Beast Master

222 |

223 | Karroch was born a child of the stocks. His mother died in childbirth; 224 | his father, a farrier for the Mad King of Slom, was trampled to death 225 | when he was five. Afterward Karroch was indentured to the king’s 226 | menagerie, where he grew up among all the beasts of the royal court: 227 | lions, apes, fell-deer, and things less known, things barely believed 228 | in. When the lad was seven, an explorer brought in a beast like none 229 | before seen. Dragged before the King in chains, the beast spoke, 230 | though its mouth moved not. Its words: a plea for freedom. The King 231 | only laughed and ordered the beast perform for his amusement; and when 232 | it refused, struck it with the Mad Scepter and ordered it dragged to 233 | the stocks. Over the coming months, the boy Karroch sneaked food and 234 | medicinal draughts to the wounded creature, but only managed to slow 235 | its deterioration. Wordlessly, the beast spoke to the boy, and over 236 | time their bond strengthened until the boy found he could hold up his 237 | end of a conversation--could in fact speak now to all the creatures of 238 | the King's menagerie. On the night the beast died, a rage came over 239 | the boy. He incited the animals of the court to rebel and threw open 240 | their cages to set them amok on the palace grounds. The Mad King was 241 | mauled in the mayhem. In the chaos, one regal stag bowed to the boy 242 | who had freed him; and with Beastmaster astride him, leapt the high 243 | walls of the estate, and escaped. Now a man, Karroch the Beastmaster 244 | has not lost his ability to converse with wild creatures. He has grown 245 | into a warrior at one with nature’s savagery. 246 |

247 |

248 | 卡洛克自出生伊始就被当做兽婴。他的母亲在他出生时就死去;他的父亲是狂王斯洛姆的马蹄铁匠,在他五岁时被马群践踏致死。后来,卡洛克将自己卖到国王的动物园干活,在那里,他和宫廷里面饲养的狮子,猩猩,野鹿以及其他一些很少见的甚至传说中的野兽一起长大。在他七岁那年,一个冒险者带着一只没人见过的野兽来觐见国王。当这只野兽被国王的链条锁住的时候,它说话了,乞求自由,然而它的嘴并没有张开。国王大笑,命令野兽表演助兴,遭到拒绝以后,国王用他的疯狂权杖狠狠的抽打了野兽,并把它关在了兽栏里面。接下来的几个月里,卡洛克每天都给这个受伤的野兽偷偷的带去食物和药物,然而这一切只能减缓野兽的死亡。这只野兽和卡洛克开始了交流,无言的交流,他们之间的情感纽带也随着时间的推移而加深,最后卡洛克发现他竟然能够和宫廷动物园里面的所有动物交流。在那只野兽死去的晚上,卡洛克狂怒无比,他煽动了所有的动物一起反叛,并且将它们的笼子打开,在宫廷广场上大开杀戒。狂王在动乱中受伤。在混乱之中,一只皇家雄鹿在这个救了它的男孩面前屈膝,让他以兽王的身份骑上它,带他跃过了堡垒的高墙,逃出生天。现在,兽王卡洛克已经成长为一个男子汉,并且仍然能够自由的和野生动物交谈。他已经成为了拥有自然狂猛野性的战士。 249 |

250 | 251 |

Dark Seer

252 |

253 | Fast when he needs to be, and a cunning strategist, Ish'Kafel the Dark 254 | Seer requires no edged weapons to vanquish his enemies, relying 255 | instead on the strength of his powerful mind. His talent lies in his 256 | ability to maneuver the fight to his advantage. Hailing from a place 257 | he calls 'The Land behind the wall,' Dark Seer remains an outsider 258 | here—a warrior from a realm beyond the veil of this reality. Once a 259 | great general among his people, and a valiant defender of the god-king 260 | Damathryx, Dark Seer’s army was wiped out by a much larger force in 261 | the final days of the Great Boundaries War. Facing certain defeat, he 262 | made one last desperate act: he led the enemy forces into the maze 263 | between the walls. At the last moment, just before capture, he crossed 264 | over—then sealed the walls forever in an explosive release of dark 265 | energy. When the dust settled, he saw that he had saved his people but 266 | found himself blinking at the sun of a different world, with no way to 267 | return. Now he is committed to proving his worth as a military 268 | strategist, and vows to show that he’s the greatest tactician this 269 | strange new world has ever seen. 270 |

271 |

272 | 迅捷如风,足智多谋,黑暗贤者依什卡菲尔并不需要多么锋利的武器来搏斗,他总是运用强大的心灵之力来征服敌人。他有着颠覆战局使之对己方有利的天才。迎着欢呼和敬意,他从一个叫做“幻墙之末”的世界走了出来,并不热衷于这个世界的纷争——他是一个来自现实世界之外的勇者。曾经,黑暗贤者是备受人民尊敬的将军,是神王达玛瑞克斯麾下英勇的保卫者,然而他的军队在边境大战的最后几天,被一股更为强大的力量悉数歼灭。面临如此惨败,他绝望的做出了最后一个决定:引诱着敌军进入了幻墙迷宫。在他即将被捕的前一刻,他穿过幻墙,释放出强大的黑暗能量,将幻墙永远的封印起来。当飞扬的尘土归于平静以后,他发现他成功的拯救了自己的人民,而自己却沐浴在另一个世界的阳光下,亦真亦幻,无法回到现实世界。现在,他决心以一名战略家的身份来证明自己的价值,并且立誓要让这个新的世界见识他那伟大的谋略。 273 |

274 |
275 |
276 | 277 | 278 | 328 | 329 | 330 | -------------------------------------------------------------------------------- /js/html2canvas.js: -------------------------------------------------------------------------------- 1 | !(function (e) { 2 | if ("object" == typeof exports && "undefined" != typeof module) 3 | module.exports = e(); 4 | else if ("function" == typeof define && define.amd) define([], e); 5 | else { 6 | var f; 7 | "undefined" != typeof window 8 | ? (f = window) 9 | : "undefined" != typeof global 10 | ? (f = global) 11 | : "undefined" != typeof self && (f = self), 12 | (f.html2canvas = e()); 13 | } 14 | })(function () { 15 | var define, module, exports; 16 | return (function e(t, n, r) { 17 | function s(o, u) { 18 | if (!n[o]) { 19 | if (!t[o]) { 20 | var a = typeof require == "function" && require; 21 | if (!u && a) return a(o, !0); 22 | if (i) return i(o, !0); 23 | var f = new Error("Cannot find module '" + o + "'"); 24 | throw ((f.code = "MODULE_NOT_FOUND"), f); 25 | } 26 | var l = (n[o] = { exports: {} }); 27 | t[o][0].call( 28 | l.exports, 29 | function (e) { 30 | var n = t[o][1][e]; 31 | return s(n ? n : e); 32 | }, 33 | l, 34 | l.exports, 35 | e, 36 | t, 37 | n, 38 | r 39 | ); 40 | } 41 | return n[o].exports; 42 | } 43 | var i = typeof require == "function" && require; 44 | for (var o = 0; o < r.length; o++) s(r[o]); 45 | return s; 46 | })( 47 | { 48 | 1: [ 49 | function (_dereq_, module, exports) { 50 | (function (global) { 51 | /*! http://mths.be/punycode v1.2.4 by @mathias */ 52 | (function (root) { 53 | /** Detect free variables */ 54 | var freeExports = typeof exports == "object" && exports; 55 | var freeModule = 56 | typeof module == "object" && 57 | module && 58 | module.exports == freeExports && 59 | module; 60 | var freeGlobal = typeof global == "object" && global; 61 | if ( 62 | freeGlobal.global === freeGlobal || 63 | freeGlobal.window === freeGlobal 64 | ) { 65 | root = freeGlobal; 66 | } 67 | 68 | /** 69 | * The `punycode` object. 70 | * @name punycode 71 | * @type Object 72 | */ 73 | var punycode, 74 | /** Highest positive signed 32-bit float value */ 75 | maxInt = 2147483647, // aka. 0x7FFFFFFF or 2^31-1 76 | /** Bootstring parameters */ 77 | base = 36, 78 | tMin = 1, 79 | tMax = 26, 80 | skew = 38, 81 | damp = 700, 82 | initialBias = 72, 83 | initialN = 128, // 0x80 84 | delimiter = "-", // '\x2D' 85 | /** Regular expressions */ 86 | regexPunycode = /^xn--/, 87 | regexNonASCII = /[^ -~]/, // unprintable ASCII chars + non-ASCII chars 88 | regexSeparators = /\x2E|\u3002|\uFF0E|\uFF61/g, // RFC 3490 separators 89 | /** Error messages */ 90 | errors = { 91 | overflow: "Overflow: input needs wider integers to process", 92 | "not-basic": "Illegal input >= 0x80 (not a basic code point)", 93 | "invalid-input": "Invalid input", 94 | }, 95 | /** Convenience shortcuts */ 96 | baseMinusTMin = base - tMin, 97 | floor = Math.floor, 98 | stringFromCharCode = String.fromCharCode, 99 | /** Temporary variable */ 100 | key; 101 | 102 | /*--------------------------------------------------------------------------*/ 103 | 104 | /** 105 | * A generic error utility function. 106 | * @private 107 | * @param {String} type The error type. 108 | * @returns {Error} Throws a `RangeError` with the applicable error message. 109 | */ 110 | function error(type) { 111 | throw RangeError(errors[type]); 112 | } 113 | 114 | /** 115 | * A generic `Array#map` utility function. 116 | * @private 117 | * @param {Array} array The array to iterate over. 118 | * @param {Function} callback The function that gets called for every array 119 | * item. 120 | * @returns {Array} A new array of values returned by the callback function. 121 | */ 122 | function map(array, fn) { 123 | var length = array.length; 124 | while (length--) { 125 | array[length] = fn(array[length]); 126 | } 127 | return array; 128 | } 129 | 130 | /** 131 | * A simple `Array#map`-like wrapper to work with domain name strings. 132 | * @private 133 | * @param {String} domain The domain name. 134 | * @param {Function} callback The function that gets called for every 135 | * character. 136 | * @returns {Array} A new string of characters returned by the callback 137 | * function. 138 | */ 139 | function mapDomain(string, fn) { 140 | return map(string.split(regexSeparators), fn).join("."); 141 | } 142 | 143 | /** 144 | * Creates an array containing the numeric code points of each Unicode 145 | * character in the string. While JavaScript uses UCS-2 internally, 146 | * this function will convert a pair of surrogate halves (each of which 147 | * UCS-2 exposes as separate characters) into a single code point, 148 | * matching UTF-16. 149 | * @see `punycode.ucs2.encode` 150 | * @see 151 | * @memberOf punycode.ucs2 152 | * @name decode 153 | * @param {String} string The Unicode input string (UCS-2). 154 | * @returns {Array} The new array of code points. 155 | */ 156 | function ucs2decode(string) { 157 | var output = [], 158 | counter = 0, 159 | length = string.length, 160 | value, 161 | extra; 162 | while (counter < length) { 163 | value = string.charCodeAt(counter++); 164 | if (value >= 0xd800 && value <= 0xdbff && counter < length) { 165 | // high surrogate, and there is a next character 166 | extra = string.charCodeAt(counter++); 167 | if ((extra & 0xfc00) == 0xdc00) { 168 | // low surrogate 169 | output.push( 170 | ((value & 0x3ff) << 10) + (extra & 0x3ff) + 0x10000 171 | ); 172 | } else { 173 | // unmatched surrogate; only append this code unit, in case the next 174 | // code unit is the high surrogate of a surrogate pair 175 | output.push(value); 176 | counter--; 177 | } 178 | } else { 179 | output.push(value); 180 | } 181 | } 182 | return output; 183 | } 184 | 185 | /** 186 | * Creates a string based on an array of numeric code points. 187 | * @see `punycode.ucs2.decode` 188 | * @memberOf punycode.ucs2 189 | * @name encode 190 | * @param {Array} codePoints The array of numeric code points. 191 | * @returns {String} The new Unicode string (UCS-2). 192 | */ 193 | function ucs2encode(array) { 194 | return map(array, function (value) { 195 | var output = ""; 196 | if (value > 0xffff) { 197 | value -= 0x10000; 198 | output += stringFromCharCode( 199 | ((value >>> 10) & 0x3ff) | 0xd800 200 | ); 201 | value = 0xdc00 | (value & 0x3ff); 202 | } 203 | output += stringFromCharCode(value); 204 | return output; 205 | }).join(""); 206 | } 207 | 208 | /** 209 | * Converts a basic code point into a digit/integer. 210 | * @see `digitToBasic()` 211 | * @private 212 | * @param {Number} codePoint The basic numeric code point value. 213 | * @returns {Number} The numeric value of a basic code point (for use in 214 | * representing integers) in the range `0` to `base - 1`, or `base` if 215 | * the code point does not represent a value. 216 | */ 217 | function basicToDigit(codePoint) { 218 | if (codePoint - 48 < 10) { 219 | return codePoint - 22; 220 | } 221 | if (codePoint - 65 < 26) { 222 | return codePoint - 65; 223 | } 224 | if (codePoint - 97 < 26) { 225 | return codePoint - 97; 226 | } 227 | return base; 228 | } 229 | 230 | /** 231 | * Converts a digit/integer into a basic code point. 232 | * @see `basicToDigit()` 233 | * @private 234 | * @param {Number} digit The numeric value of a basic code point. 235 | * @returns {Number} The basic code point whose value (when used for 236 | * representing integers) is `digit`, which needs to be in the range 237 | * `0` to `base - 1`. If `flag` is non-zero, the uppercase form is 238 | * used; else, the lowercase form is used. The behavior is undefined 239 | * if `flag` is non-zero and `digit` has no uppercase form. 240 | */ 241 | function digitToBasic(digit, flag) { 242 | // 0..25 map to ASCII a..z or A..Z 243 | // 26..35 map to ASCII 0..9 244 | return digit + 22 + 75 * (digit < 26) - ((flag != 0) << 5); 245 | } 246 | 247 | /** 248 | * Bias adaptation function as per section 3.4 of RFC 3492. 249 | * http://tools.ietf.org/html/rfc3492#section-3.4 250 | * @private 251 | */ 252 | function adapt(delta, numPoints, firstTime) { 253 | var k = 0; 254 | delta = firstTime ? floor(delta / damp) : delta >> 1; 255 | delta += floor(delta / numPoints); 256 | for ( 257 | ; 258 | /* no initialization */ delta > (baseMinusTMin * tMax) >> 1; 259 | k += base 260 | ) { 261 | delta = floor(delta / baseMinusTMin); 262 | } 263 | return floor( 264 | k + ((baseMinusTMin + 1) * delta) / (delta + skew) 265 | ); 266 | } 267 | 268 | /** 269 | * Converts a Punycode string of ASCII-only symbols to a string of Unicode 270 | * symbols. 271 | * @memberOf punycode 272 | * @param {String} input The Punycode string of ASCII-only symbols. 273 | * @returns {String} The resulting string of Unicode symbols. 274 | */ 275 | function decode(input) { 276 | // Don't use UCS-2 277 | var output = [], 278 | inputLength = input.length, 279 | out, 280 | i = 0, 281 | n = initialN, 282 | bias = initialBias, 283 | basic, 284 | j, 285 | index, 286 | oldi, 287 | w, 288 | k, 289 | digit, 290 | t, 291 | /** Cached calculation results */ 292 | baseMinusT; 293 | 294 | // Handle the basic code points: let `basic` be the number of input code 295 | // points before the last delimiter, or `0` if there is none, then copy 296 | // the first basic code points to the output. 297 | 298 | basic = input.lastIndexOf(delimiter); 299 | if (basic < 0) { 300 | basic = 0; 301 | } 302 | 303 | for (j = 0; j < basic; ++j) { 304 | // if it's not a basic code point 305 | if (input.charCodeAt(j) >= 0x80) { 306 | error("not-basic"); 307 | } 308 | output.push(input.charCodeAt(j)); 309 | } 310 | 311 | // Main decoding loop: start just after the last delimiter if any basic code 312 | // points were copied; start at the beginning otherwise. 313 | 314 | for ( 315 | index = basic > 0 ? basic + 1 : 0; 316 | index < inputLength /* no final expression */; 317 | 318 | ) { 319 | // `index` is the index of the next character to be consumed. 320 | // Decode a generalized variable-length integer into `delta`, 321 | // which gets added to `i`. The overflow checking is easier 322 | // if we increase `i` as we go, then subtract off its starting 323 | // value at the end to obtain `delta`. 324 | for ( 325 | oldi = i, w = 1, k = base /* no condition */; 326 | ; 327 | k += base 328 | ) { 329 | if (index >= inputLength) { 330 | error("invalid-input"); 331 | } 332 | 333 | digit = basicToDigit(input.charCodeAt(index++)); 334 | 335 | if (digit >= base || digit > floor((maxInt - i) / w)) { 336 | error("overflow"); 337 | } 338 | 339 | i += digit * w; 340 | t = k <= bias ? tMin : k >= bias + tMax ? tMax : k - bias; 341 | 342 | if (digit < t) { 343 | break; 344 | } 345 | 346 | baseMinusT = base - t; 347 | if (w > floor(maxInt / baseMinusT)) { 348 | error("overflow"); 349 | } 350 | 351 | w *= baseMinusT; 352 | } 353 | 354 | out = output.length + 1; 355 | bias = adapt(i - oldi, out, oldi == 0); 356 | 357 | // `i` was supposed to wrap around from `out` to `0`, 358 | // incrementing `n` each time, so we'll fix that now: 359 | if (floor(i / out) > maxInt - n) { 360 | error("overflow"); 361 | } 362 | 363 | n += floor(i / out); 364 | i %= out; 365 | 366 | // Insert `n` at position `i` of the output 367 | output.splice(i++, 0, n); 368 | } 369 | 370 | return ucs2encode(output); 371 | } 372 | 373 | /** 374 | * Converts a string of Unicode symbols to a Punycode string of ASCII-only 375 | * symbols. 376 | * @memberOf punycode 377 | * @param {String} input The string of Unicode symbols. 378 | * @returns {String} The resulting Punycode string of ASCII-only symbols. 379 | */ 380 | function encode(input) { 381 | var n, 382 | delta, 383 | handledCPCount, 384 | basicLength, 385 | bias, 386 | j, 387 | m, 388 | q, 389 | k, 390 | t, 391 | currentValue, 392 | output = [], 393 | /** `inputLength` will hold the number of code points in `input`. */ 394 | inputLength, 395 | /** Cached calculation results */ 396 | handledCPCountPlusOne, 397 | baseMinusT, 398 | qMinusT; 399 | 400 | // Convert the input in UCS-2 to Unicode 401 | input = ucs2decode(input); 402 | 403 | // Cache the length 404 | inputLength = input.length; 405 | 406 | // Initialize the state 407 | n = initialN; 408 | delta = 0; 409 | bias = initialBias; 410 | 411 | // Handle the basic code points 412 | for (j = 0; j < inputLength; ++j) { 413 | currentValue = input[j]; 414 | if (currentValue < 0x80) { 415 | output.push(stringFromCharCode(currentValue)); 416 | } 417 | } 418 | 419 | handledCPCount = basicLength = output.length; 420 | 421 | // `handledCPCount` is the number of code points that have been handled; 422 | // `basicLength` is the number of basic code points. 423 | 424 | // Finish the basic string - if it is not empty - with a delimiter 425 | if (basicLength) { 426 | output.push(delimiter); 427 | } 428 | 429 | // Main encoding loop: 430 | while (handledCPCount < inputLength) { 431 | // All non-basic code points < n have been handled already. Find the next 432 | // larger one: 433 | for (m = maxInt, j = 0; j < inputLength; ++j) { 434 | currentValue = input[j]; 435 | if (currentValue >= n && currentValue < m) { 436 | m = currentValue; 437 | } 438 | } 439 | 440 | // Increase `delta` enough to advance the decoder's state to , 441 | // but guard against overflow 442 | handledCPCountPlusOne = handledCPCount + 1; 443 | if (m - n > floor((maxInt - delta) / handledCPCountPlusOne)) { 444 | error("overflow"); 445 | } 446 | 447 | delta += (m - n) * handledCPCountPlusOne; 448 | n = m; 449 | 450 | for (j = 0; j < inputLength; ++j) { 451 | currentValue = input[j]; 452 | 453 | if (currentValue < n && ++delta > maxInt) { 454 | error("overflow"); 455 | } 456 | 457 | if (currentValue == n) { 458 | // Represent delta as a generalized variable-length integer 459 | for ( 460 | q = delta, k = base /* no condition */; 461 | ; 462 | k += base 463 | ) { 464 | t = 465 | k <= bias ? tMin : k >= bias + tMax ? tMax : k - bias; 466 | if (q < t) { 467 | break; 468 | } 469 | qMinusT = q - t; 470 | baseMinusT = base - t; 471 | output.push( 472 | stringFromCharCode( 473 | digitToBasic(t + (qMinusT % baseMinusT), 0) 474 | ) 475 | ); 476 | q = floor(qMinusT / baseMinusT); 477 | } 478 | 479 | output.push(stringFromCharCode(digitToBasic(q, 0))); 480 | bias = adapt( 481 | delta, 482 | handledCPCountPlusOne, 483 | handledCPCount == basicLength 484 | ); 485 | delta = 0; 486 | ++handledCPCount; 487 | } 488 | } 489 | 490 | ++delta; 491 | ++n; 492 | } 493 | return output.join(""); 494 | } 495 | 496 | /** 497 | * Converts a Punycode string representing a domain name to Unicode. Only the 498 | * Punycoded parts of the domain name will be converted, i.e. it doesn't 499 | * matter if you call it on a string that has already been converted to 500 | * Unicode. 501 | * @memberOf punycode 502 | * @param {String} domain The Punycode domain name to convert to Unicode. 503 | * @returns {String} The Unicode representation of the given Punycode 504 | * string. 505 | */ 506 | function toUnicode(domain) { 507 | return mapDomain(domain, function (string) { 508 | return regexPunycode.test(string) 509 | ? decode(string.slice(4).toLowerCase()) 510 | : string; 511 | }); 512 | } 513 | 514 | /** 515 | * Converts a Unicode string representing a domain name to Punycode. Only the 516 | * non-ASCII parts of the domain name will be converted, i.e. it doesn't 517 | * matter if you call it with a domain that's already in ASCII. 518 | * @memberOf punycode 519 | * @param {String} domain The domain name to convert, as a Unicode string. 520 | * @returns {String} The Punycode representation of the given domain name. 521 | */ 522 | function toASCII(domain) { 523 | return mapDomain(domain, function (string) { 524 | return regexNonASCII.test(string) 525 | ? "xn--" + encode(string) 526 | : string; 527 | }); 528 | } 529 | 530 | /*--------------------------------------------------------------------------*/ 531 | 532 | /** Define the public API */ 533 | punycode = { 534 | /** 535 | * A string representing the current Punycode.js version number. 536 | * @memberOf punycode 537 | * @type String 538 | */ 539 | version: "1.2.4", 540 | /** 541 | * An object of methods to convert from JavaScript's internal character 542 | * representation (UCS-2) to Unicode code points, and back. 543 | * @see 544 | * @memberOf punycode 545 | * @type Object 546 | */ 547 | ucs2: { 548 | decode: ucs2decode, 549 | encode: ucs2encode, 550 | }, 551 | decode: decode, 552 | encode: encode, 553 | toASCII: toASCII, 554 | toUnicode: toUnicode, 555 | }; 556 | 557 | /** Expose `punycode` */ 558 | // Some AMD build optimizers, like r.js, check for specific condition patterns 559 | // like the following: 560 | if ( 561 | typeof define == "function" && 562 | typeof define.amd == "object" && 563 | define.amd 564 | ) { 565 | define("punycode", function () { 566 | return punycode; 567 | }); 568 | } else if (freeExports && !freeExports.nodeType) { 569 | if (freeModule) { 570 | // in Node.js or RingoJS v0.8.0+ 571 | freeModule.exports = punycode; 572 | } else { 573 | // in Narwhal or RingoJS v0.7.0- 574 | for (key in punycode) { 575 | punycode.hasOwnProperty(key) && 576 | (freeExports[key] = punycode[key]); 577 | } 578 | } 579 | } else { 580 | // in Rhino or a web browser 581 | root.punycode = punycode; 582 | } 583 | })(this); 584 | }.call( 585 | this, 586 | typeof global !== "undefined" 587 | ? global 588 | : typeof self !== "undefined" 589 | ? self 590 | : typeof window !== "undefined" 591 | ? window 592 | : {} 593 | )); 594 | }, 595 | {}, 596 | ], 597 | 2: [ 598 | function (_dereq_, module, exports) { 599 | var log = _dereq_("./log"); 600 | 601 | function restoreOwnerScroll(ownerDocument, x, y) { 602 | if ( 603 | ownerDocument.defaultView && 604 | (x !== ownerDocument.defaultView.pageXOffset || 605 | y !== ownerDocument.defaultView.pageYOffset) 606 | ) { 607 | ownerDocument.defaultView.scrollTo(x, y); 608 | } 609 | } 610 | 611 | function cloneCanvasContents(canvas, clonedCanvas) { 612 | try { 613 | if (clonedCanvas) { 614 | clonedCanvas.width = canvas.width; 615 | clonedCanvas.height = canvas.height; 616 | clonedCanvas 617 | .getContext("2d") 618 | .putImageData( 619 | canvas 620 | .getContext("2d") 621 | .getImageData(0, 0, canvas.width, canvas.height), 622 | 0, 623 | 0 624 | ); 625 | } 626 | } catch (e) { 627 | log("Unable to copy canvas content from", canvas, e); 628 | } 629 | } 630 | 631 | function cloneNode(node, javascriptEnabled) { 632 | var clone = 633 | node.nodeType === 3 634 | ? document.createTextNode(node.nodeValue) 635 | : node.cloneNode(false); 636 | 637 | var child = node.firstChild; 638 | while (child) { 639 | if ( 640 | javascriptEnabled === true || 641 | child.nodeType !== 1 || 642 | child.nodeName !== "SCRIPT" 643 | ) { 644 | clone.appendChild(cloneNode(child, javascriptEnabled)); 645 | } 646 | child = child.nextSibling; 647 | } 648 | 649 | if (node.nodeType === 1) { 650 | clone._scrollTop = node.scrollTop; 651 | clone._scrollLeft = node.scrollLeft; 652 | if (node.nodeName === "CANVAS") { 653 | cloneCanvasContents(node, clone); 654 | } else if ( 655 | node.nodeName === "TEXTAREA" || 656 | node.nodeName === "SELECT" 657 | ) { 658 | clone.value = node.value; 659 | } 660 | } 661 | 662 | return clone; 663 | } 664 | 665 | function initNode(node) { 666 | if (node.nodeType === 1) { 667 | node.scrollTop = node._scrollTop; 668 | node.scrollLeft = node._scrollLeft; 669 | 670 | var child = node.firstChild; 671 | while (child) { 672 | initNode(child); 673 | child = child.nextSibling; 674 | } 675 | } 676 | } 677 | 678 | module.exports = function ( 679 | ownerDocument, 680 | containerDocument, 681 | width, 682 | height, 683 | options, 684 | x, 685 | y 686 | ) { 687 | var documentElement = cloneNode( 688 | ownerDocument.documentElement, 689 | options.javascriptEnabled 690 | ); 691 | var container = containerDocument.createElement("iframe"); 692 | 693 | container.className = "html2canvas-container"; 694 | container.style.visibility = "hidden"; 695 | container.style.position = "fixed"; 696 | container.style.left = "-10000px"; 697 | container.style.top = "0px"; 698 | container.style.border = "0"; 699 | container.width = width; 700 | container.height = height; 701 | container.scrolling = "no"; // ios won't scroll without it 702 | containerDocument.body.appendChild(container); 703 | 704 | return new Promise(function (resolve) { 705 | var documentClone = container.contentWindow.document; 706 | 707 | /* Chrome doesn't detect relative background-images assigned in inline