• js生成图片的多边形科技感效果


    js将图片转换为无数多边形组成的科技感图片 low poly 效果

    用多边形拟合一张图片,这种凹凸有致的科技感令人着迷,这就上图

     

     这种效果既能保护隐私,又能对形象有一个科技感的良好展示。

    在线demo地址js将图片转换为无数多边形组成的科技感图片 low poly 效果 (mubanmao.top)

    可即时上传进行展示。完全在浏览器中实现的效果。

    相关代码如下:

    index.js

    1. /**
    2. * Created by lz on 2015/5/23.
    3. */
    4. var panel = new Polyer.Panel(false);
    5. var canvas_box = document.getElementById("canvas-box"),
    6. firstCanvas = document.createElement("canvas"),
    7. secondCanvas = document.createElement("canvas"),
    8. srcs = ["./img/dog.jpg", "./img/tiger.jpg", "./img/cat.jpg"],
    9. WebGLs,
    10. points,
    11. poly;
    12. //init
    13. points = new Polyer.WebGL(firstCanvas);
    14. poly = new Polyer.WebGL(secondCanvas);
    15. WebGLs = [points, poly];
    16. canvas_box.appendChild(firstCanvas);
    17. canvas_box.appendChild(secondCanvas);
    18. //set canvas size
    19. changeMode(panel.mode);
    20. //set bg color
    21. points.setClearColor(convertHexToRGB(panel.editBgColor, true));
    22. poly.setClearColor(convertHexToRGB(panel.viewBgColor, true));
    23. //call when async points and poly both are finished
    24. var o = new Polyer.Utils.Observer("points", "poly", function () {
    25. points.setBackground(panel.bg)
    26. poly.setPolyPoints(points.getPolyPoints());
    27. poly.setDelaunayTriangles(points.getDelaunayTriangles());
    28. poly.updatePolyTriangle(panel.fillColor == "average");
    29. points.draw();
    30. poly.draw();
    31. });
    32. var img = new Image();
    33. Polyer.UITools.Alert.show("Loading Image", true, true);
    34. img.onload = function () {
    35. points.createProcessingLine(img, [{type: "gray"}, {type: "blur"}, {type: "edge"}], panel.vertexNum, function () {
    36. points.createPolyMesh(convertHexToRGB(panel.meshColor));
    37. // panel.maxVertexNum = points.getEdgePoints().length;
    38. o.emit("points");
    39. });
    40. poly.createOriginal(img, function () {
    41. o.emit("poly")
    42. })
    43. Polyer.UITools.Alert.hide();
    44. }
    45. img.src = srcs[Math.floor(Math.random() * srcs.length)];
    46. /*
    47. * bind webgls to panel events
    48. * use panel Interface to control two webgls
    49. * */
    50. panel.onModeChange = changeMode;
    51. function changeMode(mode) {
    52. var width = document.body.clientWidth,
    53. height = document.body.clientHeight;
    54. switch (mode) {
    55. case "edit" :
    56. firstCanvas.style.display = "block";
    57. secondCanvas.style.display = "none";
    58. points.resize(width, height);
    59. poly.resize(width, height);
    60. points.draw();
    61. break;
    62. case "sync" :
    63. points.resize(width / 2, height);
    64. poly.resize(width / 2, height);
    65. //put display backward because two elements show one by one
    66. // dom element will influence the calculation of document.body.width
    67. // if put it forward
    68. firstCanvas.style.display = secondCanvas.style.display = "block";
    69. points.draw();
    70. poly.draw();
    71. break;
    72. case "view" :
    73. firstCanvas.style.display = "none";
    74. secondCanvas.style.display = "block";
    75. points.resize(width, height);
    76. poly.resize(width, height);
    77. poly.draw();
    78. break;
    79. }
    80. }
    81. panel.onUseKernel = function (bluerSize, edgeSize) {
    82. var realKernel = [5, 7, 9, 11, 13],
    83. line = [{type: "gray"}, {type: "blur", kernelSize: realKernel[bluerSize - 1]}, {
    84. type: "edge",
    85. kernelSize: realKernel[edgeSize - 1]
    86. }];
    87. points.reProcessLine(line, panel.vertexNum, function () {
    88. points.setBackground(panel.bg);
    89. updateMeshAndApplyToPoly();
    90. })
    91. }
    92. panel.onBgChange = function (bg) {
    93. points.setBackground(bg);
    94. points.draw();
    95. }
    96. panel.onEditChange = function (edit) {
    97. updateCursor(edit);
    98. }
    99. panel.zoomLarger = function () {
    100. zoomLarger();
    101. }
    102. panel.zoomSmaller = function () {
    103. zoomSmaller();
    104. }
    105. panel.onVertexNumChange = function (num) {
    106. //for first panel recovery , onVertexNumChange is called in panel with delay
    107. //so panel recovery will trigger all functions those are null when recovering
    108. //after delay end , onVertexNumChange will be trigger , on this time the function
    109. //is already bind to onVertexNumChange , but the webgls maybe not ready because
    110. //these are async.
    111. //so set this judgement to cut this down.
    112. if (points.getEdgePoints().length == 0) {
    113. return;
    114. }
    115. points.setPolyPointsFromEdge(num);
    116. updateMeshAndApplyToPoly();
    117. }
    118. panel.onMeshColorChange = function (color) {
    119. points.updatePolyMeshColor(convertHexToRGB(color));
    120. points.draw();
    121. }
    122. panel.onEditBgColorChange = function (color) {
    123. points.setClearColor(convertHexToRGB(color, true))//add fourth argument for gl.clearColor
    124. points.draw();
    125. }
    126. panel.onViewBgColorChange = function (color) {
    127. poly.setClearColor(convertHexToRGB(color, true));
    128. poly.draw();
    129. }
    130. panel.onFillColorChange = function (fillWay) {
    131. if (fillWay == "average") {
    132. poly.updatePolyTriangle(true);
    133. } else {
    134. poly.updatePolyTriangle(false);
    135. }
    136. poly.draw();
    137. }
    138. panel.onImageLoaded = function (img) {
    139. if (img.width >= points.gl.MAX_TEXTURE_SIZE || img.height >= points.gl.MAX_TEXTURE_SIZE) {
    140. return Polyer.UITools.Alert.show("Please use picture which size is smaller than " + points.gl.MAX_TEXTURE_SIZE + "piels X" + points.gl.MAX_TEXTURE_SIZE + "piels for better effect !", true);
    141. }
    142. points.createProcessingLine(img, [{type: "gray"}, {type: "blur"}, {type: "edge"}], panel.vertexNum, function () {
    143. points.updatePolyMeshBasePoints();
    144. o.emit("points");
    145. });
    146. poly.createOriginal(img, function () {
    147. o.emit("poly")
    148. })
    149. }
    150. panel.onSave = function (img) {
    151. img.src = poly.saveImage();
    152. }
    153. /*
    154. * bind to canvas_box for zoom
    155. * */
    156. var zoomEvent = Polyer.Utils.debounce(function (e) {
    157. if (e.detail ? e.detail < 0 : e.wheelDelta > 0) {
    158. zoomLarger();
    159. } else {
    160. zoomSmaller();
    161. }
    162. }, 30);
    163. Polyer.Utils.bind(canvas_box, "mousewheel", zoomEvent);
    164. Polyer.Utils.bind(canvas_box, "DOMMouseScroll", zoomEvent);
    165. var mouseDetial = {
    166. isDown: false,
    167. x: 0,
    168. y: 0
    169. }
    170. /*
    171. * bind to canvas_box for "move" event
    172. * */
    173. Polyer.Utils.bind(canvas_box, "mousedown", function (e) {
    174. if (panel.edit != "move") return;
    175. mouseDetial.isDown = true;
    176. mouseDetial.x = e.pageX || e.clientX;
    177. mouseDetial.y = e.pageY || e.clientY;
    178. });
    179. Polyer.Utils.bind(canvas_box, "mousemove", Polyer.Utils.debounce(function (e) {
    180. if (panel.edit != "move" || !mouseDetial.isDown) {
    181. return;
    182. }
    183. points.drag(((e.pageX || e.clientX) - mouseDetial.x) / points.canvas.width * 2,
    184. ((e.pageY || e.clientY) - mouseDetial.y) / points.canvas.height * 2);
    185. poly.drag(((e.pageX || e.clientX) - mouseDetial.x) / poly.canvas.width * 2,
    186. ((e.pageY || e.clientY) - mouseDetial.y) / poly.canvas.height * 2);
    187. mouseDetial.x = e.pageX || e.clientX;
    188. mouseDetial.y = e.pageY || e.clientY;
    189. }, 20));
    190. Polyer.Utils.bind(canvas_box, "mouseup", function () {
    191. if (panel.edit != "move" || !mouseDetial.isDown) {
    192. return false;
    193. }
    194. mouseDetial.isDown = false;
    195. });
    196. //add tabindex to div for binding keydown
    197. //for binding keydown and keyup to document ,hover for changing edit to "move" while "remove" or "add"
    198. canvas_box.setAttribute("tabindex", 1);
    199. Polyer.Utils.bind(document, "keydown", (function () {
    200. var store = false;
    201. Polyer.Utils.bind(document, "keyup", function () {
    202. if (store) {
    203. panel.edit = store;
    204. updateCursor(store);
    205. store = false;
    206. }
    207. })
    208. return function (e) {
    209. if (panel.edit != "move" && e.keyCode == 32 && !store) {
    210. store = panel.edit;
    211. panel.edit = "move";
    212. updateCursor("move");
    213. }
    214. }
    215. })())
    216. /*
    217. * bind to firstCanvas for "remove" event
    218. * */
    219. Polyer.Utils.bind(firstCanvas, "mousedown", function (e) {
    220. //if edit tool is "move" , propagate event up to canvas_box ,
    221. //return and trigger canvas_box mousedown event
    222. //if edit tool is "click" , do not trigger mousedown
    223. //so there is only "remove" left
    224. if (panel.edit != "remove") {
    225. return;
    226. }
    227. e.stopPropagation();
    228. mouseDetial.isDown = true;
    229. points.addSelect(e.x || e.layerX || e.offsetX, e.y || e.layerY || e.offsetY);
    230. })
    231. Polyer.Utils.bind(firstCanvas, "mousemove", Polyer.Utils.debounce(function (e) {
    232. if (panel.edit != "remove" || !mouseDetial.isDown) {
    233. return;
    234. }
    235. points.updateSelect(e.x || e.layerX || e.offsetX, e.y || e.layerY || e.offsetY);
    236. }, 20));
    237. Polyer.Utils.bind(firstCanvas, "mouseup", function () {
    238. if (panel.edit != "remove" || !mouseDetial.isDown) {
    239. return;
    240. }
    241. mouseDetial.isDown = false;
    242. points.removeSelect();
    243. poly.setPolyPoints(points.getPolyPoints());
    244. poly.setDelaunayTriangles(points.getDelaunayTriangles());
    245. poly.updatePolyTriangle();
    246. poly.draw();
    247. })
    248. /*
    249. * bind to firstCanvas for "click" event
    250. * */
    251. Polyer.Utils.bind(firstCanvas, "click", function (e) {
    252. if (panel.edit != "add") return;
    253. var p = points.getPolyPoints(),
    254. coor;
    255. if (coor = points.convertCoorIntoTexture(e.offsetX || e.layerX, e.offsetY || e.layerY)) {
    256. p.push([coor.x, coor.y]);
    257. updateMeshAndApplyToPoly();
    258. }
    259. });
    260. /*
    261. * bind resize event
    262. * */
    263. Polyer.Utils.bind(window, "resize", Polyer.Utils.latestEvent(function () {
    264. var width = document.documentElement.clientWidth,
    265. height = document.documentElement.clientHeight;
    266. switch (panel.mode) {
    267. case "edit":
    268. case "view":
    269. points.resize(width, height);
    270. poly.resize(width, height);
    271. break;
    272. case "sync":
    273. points.resize(width / 2, height);
    274. poly.resize(width / 2, height);
    275. }
    276. points.draw();
    277. poly.draw();
    278. }, 100))
    279. function applyToWebGLs(func) {
    280. for (var i = 0, l = WebGLs.length; i < l; i++) {
    281. func.apply(WebGLs[i], Array.prototype.slice.call(arguments, 1));
    282. }
    283. }
    284. function zoomLarger() {
    285. applyToWebGLs(Polyer.WebGL.prototype.zoom, -0.22, -0.22);
    286. }
    287. function zoomSmaller() {
    288. applyToWebGLs(Polyer.WebGL.prototype.zoom, 0.22, 0.22);
    289. }
    290. function updateMeshAndApplyToPoly() {
    291. points.updatePolyMeshBasePoints();
    292. points.draw();
    293. //handler points array and delaunay triangles to poly
    294. poly.setPolyPoints(points.getPolyPoints());
    295. poly.setDelaunayTriangles(points.getDelaunayTriangles());
    296. poly.updatePolyTriangle();
    297. poly.draw();
    298. }
    299. function updateCursor(edit) {
    300. if (edit == "move") {
    301. canvas_box.className = "move";
    302. } else {
    303. canvas_box.className = "edit";
    304. }
    305. }
    306. function convertHexToRGB(color, addAlpha) {
    307. //convert hex to rgb then convert to float format
    308. var array = color.match(/\w{2}/ig),
    309. i = array.length;
    310. while (i--) {
    311. array[i] = parseInt(array[i], 16) / 255;
    312. }
    313. addAlpha && array.push(1);
    314. return array;
    315. }

  • 相关阅读:
    重磅!首例植入配备 BCI 的神经刺激器的患者恢复手臂功能
    k8s--基础--6.2--环境搭建--单master高可用集群
    代码大全阅读随笔(四)
    AtCoder Beginner Contest 279 G. At Most 2 Colors(计数/组合数学/dp递推)
    智慧城市的发展趋势
    Centos7 内核升级(5.4.225)
    STM32中的加速度计驱动程序与姿态控制实现
    Python图像处理丨带你掌握图像几何变换
    人大金融创新研究中心携手能链科技联合成立#中国区块链研究会#
    数据中台的五个关键要素
  • 原文地址:https://blog.csdn.net/kongzhonghu/article/details/126878589