PPIL

Pixel Place Image Loader

此脚本不应直接安装,它是一个供其他脚本使用的外部库。如果您需要使用该库,请在脚本元属性加入:// @require https://update.cn-greasyfork.org/scripts/443894/1050256/PPIL.js

  1. // ==UserScript==
  2. // @name PPIL
  3. // @description Pixel Place Image Loader
  4. // @version 1.6.2
  5. // @author 0vC4
  6. // @namespace https://greasyfork.org/users/670183
  7. // @match https://pixelplace.io/*
  8. // @icon https://www.google.com/s2/favicons?sz=64&domain=pixelplace.io
  9. // @license MIT
  10. // @grant none
  11. // @run-at document-start
  12. // ==/UserScript==
  13. (() => {
  14. const PPClient = window.PPClient || {modules:{}};
  15. window.PPClient = PPClient;
  16. if ('ImageLoader' in PPClient.modules) return;
  17.  
  18. const progressManager = func => {
  19. const callbacks = {};
  20. const root = new Proxy({}, {
  21. get(target, key) {
  22. if (!target[key]) target[key] = callback => (callbacks[key] = callback, root);
  23. return target[key];
  24. }
  25. });
  26. root.start = (...args) => func(callbacks)(...args);
  27. return root;
  28. };
  29.  
  30. const worker = progressManager(({progress=()=>0, finish=()=>0}) =>
  31. (data, func) => {
  32. const worker = new Worker(URL.createObjectURL(new Blob([`
  33. const progress = value => self.postMessage({progress:true,value});
  34. const finish = value => self.postMessage({finish:true,value});
  35. onmessage = async ({data}) => {
  36. await (${func.toString()})(data);
  37. close();
  38. };
  39. `], { type: "text/javascript" })));
  40. worker.addEventListener('message', ({data}) => data.progress && progress(data.value));
  41. worker.addEventListener('message', ({data}) => data.finish && finish(data.value));
  42. worker.postMessage(data);
  43. });
  44.  
  45. const module = {};
  46. module.args = {};
  47. module.config = ({colors, exclude, zero}) =>
  48. Object.assign(module.args, {colors, exclude, zero});
  49.  
  50.  
  51.  
  52. module.imageToPixels = progressManager(({progress=()=>0, finish=()=>0, silent=true}) =>
  53. (img,w,h) => {
  54. let {width, height} = img;
  55. if (w != null) width = w;
  56. if (h != null) height = h;
  57.  
  58. const canvas = document.createElement('canvas');
  59. canvas.width = width;
  60. canvas.height = height;
  61. const ctx = canvas.getContext('2d');
  62. ctx.drawImage(img, 0, 0, width, height);
  63. const rgba = ctx.getImageData(0, 0, width, height).data;
  64.  
  65. worker.progress(progress).finish(finish).start(
  66. {rgba, width,height, silent, ...module.args},
  67. async ({rgba, width,height, silent, colors,exclude,zero}) => {
  68. const palette = [...colors.map(p => exclude.includes(p) ? zero : p)]
  69. .filter(p => p != zero)
  70. .map(clr => [(clr>>16)&0xFF, (clr>>8)&0xFF, clr&0xFF]);
  71.  
  72. const toPixel = (r, g, b) => colors.indexOf(
  73. palette
  74. .map(([r2, g2, b2]) => ((r2-r)**2 + (g2-g)**2 + (b2-b)**2)*0x1000000 + (r2<<16) + (g2<<8) + b2)
  75. .sort((a,b) => a-b)[0] & 0xFFFFFF
  76. );
  77.  
  78. const pixels = new Uint8Array(rgba.length>>2);
  79. for (let i = 0; i < rgba.length; i += 4) {
  80. silent || progress(i/rgba.length);
  81. pixels[i>>2] = rgba[i+3] >= 0xAA ? toPixel(rgba[i], rgba[i+1], rgba[i+2]) : -1;
  82. }
  83.  
  84. finish([pixels, width, height]);
  85. });
  86. });
  87.  
  88.  
  89.  
  90. module.loadImage = progressManager(({progress=()=>0, finish=()=>0, silent=true}) =>
  91. (w, h) => {
  92. const dropArea = document.createElement('div');
  93. top.document.body.appendChild(dropArea);
  94. dropArea.style = "width: calc(100% - 2em);height: calc(100% - 2em);position: fixed;left: 0px;top: 0px;background-color: rgba(0, 0, 0, 0.533);z-index: 9999;display: flex;color: white;font-size: 48pt;justify-content: center;align-items: center;border: 3px white dashed;border-radius: 18px;margin: 1em;";
  95. dropArea.textContent = "Drop Image";
  96. dropArea.onclick = e => dropArea.remove();
  97.  
  98. ['dragenter','dragover','dragleave','drop'].forEach(eName =>
  99. dropArea.addEventListener(eName, e => {
  100. e.preventDefault();
  101. e.stopPropagation();
  102. }, false)
  103. );
  104.  
  105. dropArea.addEventListener('drop', e => {
  106. const reader = new FileReader();
  107. reader.readAsDataURL(e.dataTransfer.files[0]);
  108. reader.onload = e => {
  109. const img = new Image;
  110. img.src = reader.result;
  111. img.onload = e => module.imageToPixels.silent(silent).progress(progress).finish(finish).start(img,w,h);
  112. };
  113. dropArea.remove();
  114. },false);
  115. });
  116.  
  117.  
  118.  
  119. PPClient.modules.ImageLoader = module;
  120. })();
  121. // 0vC4#7152