Advertisement
Guest User

Untitled

a guest
Jan 11th, 2021
102
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  1. const CONSTS = {
  2.   OUTPUT_IMG_WIDTH: 5001,
  3.   OUTPUT_IMG_HEIGHT: 5001,
  4.   SPIRAL_DENSITY: 0.35,
  5.   MODULATION_FORCE: 25,
  6.   MODULATION_POS_OFFSET: 3,
  7.   MODULATION_NEG_OFFSET: 3,
  8.   SPIRAL_COLOR_R: 127,
  9.   SPIRAL_COLOR_G: 127,
  10.   SPIRAL_COLOR_B: 127,
  11.  
  12. /* don't change these constans */
  13.   INVALID_COORDINATE: -1
  14. };
  15.  
  16. Object.freeze(CONSTS);
  17.  
  18. class Position{
  19.   constructor(){
  20.     this.x = CONSTS.INVALID_COORDINATE;
  21.     this.y = CONSTS.INVALID_COORDINATE;
  22.   }
  23.  
  24.   init_position(){
  25.     this.x = CONSTS.INVALID_COORDINATE;
  26.     this.y = CONSTS.INVALID_COORDINATE;
  27.   }
  28.  
  29.   is_position_empty(){
  30.     return CONSTS.INVALID_COORDINATE === this.x && CONSTS.INVALID_COORDINATE === this.y;
  31.   }
  32.  
  33.   copy(other){
  34.     this.x = other.x;
  35.     this.y = other.y;
  36.   }
  37.  
  38.   is_valid(){
  39.     return this.x >= 0 && this.x < CONSTS.OUTPUT_IMG_WIDTH && this.y >= 0 && this.y < CONSTS.OUTPUT_IMG_HEIGHT;
  40.   }
  41. }
  42.  
  43. function put_pixel(x, y, output_map){
  44.   output_map[4 * y * CONSTS.OUTPUT_IMG_WIDTH + 4 * x    ] = CONSTS.SPIRAL_COLOR_R;
  45.   output_map[4 * y * CONSTS.OUTPUT_IMG_WIDTH + 4 * x + 1] = CONSTS.SPIRAL_COLOR_G;
  46.   output_map[4 * y * CONSTS.OUTPUT_IMG_WIDTH + 4 * x + 2] = CONSTS.SPIRAL_COLOR_B;
  47.   output_map[4 * y * CONSTS.OUTPUT_IMG_WIDTH + 4 * x + 3] = 255;
  48. }
  49.  
  50. function draw_line_x(a, b, output_map){
  51.   var x = 0;
  52.   var l_slope = 1;
  53.  
  54.   if(a.x < b.x){
  55.     l_slope = (b.y - a.y) / (b.x - a.x);
  56.  
  57.     for(x = a.x; x <= b.x; x++){
  58.       put_pixel(x, parseInt(a.y + (x - a.x) * l_slope), output_map);
  59.     }
  60.   }
  61.   else{
  62.     l_slope = (a.y - b.y) / (a.x - b.x);
  63.  
  64.     for(x = b.x; x <= a.x; x++){
  65.       put_pixel(x, parseInt(b.y + (x - b.x) * l_slope), output_map);
  66.     }
  67.   }
  68. }
  69.  
  70. function draw_line_y(a, b, output_map){
  71.   var y = 0;
  72.   var l_slope = 1;
  73.  
  74.   if(a.y < b.y){
  75.     l_slope = (b.y - a.y) / (b.x - a.x);
  76.  
  77.     for(y = a.y; y <= b.y; y++){
  78.       put_pixel(a.x + parseInt((y - a.y) / l_slope), y, output_map);
  79.     }
  80.   }
  81.   else{
  82.     l_slope = (a.y - b.y) / (a.x - b.x);
  83.  
  84.     for(y = b.y; y <= a.y; y++){
  85.       put_pixel(b.x + parseInt((y - b.y) / l_slope), y, output_map);
  86.     }
  87.   }
  88. }
  89.  
  90. function draw_line(a, b, output_map){
  91.   var x = 0;
  92.   var y = 0;
  93.  
  94.   if(!a.is_valid() || !b.is_valid()){
  95.     return;
  96.   }
  97.  
  98.   if(a.x === b.x){
  99.     for(y = Math.min(a.y, b.y); y <= Math.max(a.y, b.y); y++){
  100.       put_pixel(a.x, y, output_map);
  101.     }
  102.   }
  103.   else if(a.y === b.y){
  104.     for(x = Math.min(a.x, b.x); x <= Math.max(a.x, b.x); x++){
  105.       put_pixel(x, a.y, output_map);
  106.     }
  107.   }
  108.   else if(Math.abs(a.x - b.x) > Math.abs(a.y - b.y)){
  109.     draw_line_x(a, b, output_map);
  110.   }
  111.   else{
  112.     draw_line_y(a, b, output_map);
  113.   }
  114. }
  115.  
  116. function create_spiral_pair(modulation_map, angle, output_map, outer_spiral_start){
  117.   var l_rotation = 0;
  118.   var l_angle = 0;
  119.   var l_radius = 0;
  120.   var l_inner_radius = 0;
  121.   var l_outer_radius = 0;
  122.   var l_modulation = 0;
  123.   var l_angle_step = 0;
  124.   var l_inverted_lightness = 0;
  125.   var l_pixel = new Position();
  126.   var l_inner_pixel = new Position();
  127.   var l_outer_pixel = new Position();
  128.   var l_old_inner_pixel = new Position();
  129.   var l_old_outer_pixel = new Position();
  130.  
  131.   for(l_rotation = 0; 360 * CONSTS.SPIRAL_DENSITY * l_rotation + 360 * CONSTS.SPIRAL_DENSITY < Math.min(CONSTS.OUTPUT_IMG_WIDTH / 2 - 10, CONSTS.OUTPUT_IMG_HEIGHT / 2 - 10); l_rotation++){
  132.     l_angle_step = 360 * Math.atan(1 / (360 * CONSTS.SPIRAL_DENSITY * (l_rotation + 1))) / (2 * Math.PI);
  133.  
  134.     for(l_angle = 0; l_angle < 360; l_angle += l_angle_step){
  135.       l_radius = 360 * CONSTS.SPIRAL_DENSITY * l_rotation + l_angle * CONSTS.SPIRAL_DENSITY;
  136.  
  137.       l_pixel.x = parseInt(l_radius * Math.sin(2 * Math.PI * (l_angle + angle) / 360) + CONSTS.OUTPUT_IMG_WIDTH / 2 + 1);
  138.       l_pixel.y = parseInt(l_radius * Math.cos(2 * Math.PI * (l_angle + angle) / 360) + CONSTS.OUTPUT_IMG_HEIGHT / 2 + 1);
  139.  
  140.       if(0 === modulation_map[4 * l_pixel.y * CONSTS.OUTPUT_IMG_WIDTH + 4 * l_pixel.x + 3]){
  141.         l_inverted_lightness = 0;
  142.       }
  143.       else{
  144.         l_inverted_lightness = 255 - parseInt(0.2126 * modulation_map[4 * l_pixel.y * CONSTS.OUTPUT_IMG_WIDTH + 4 * l_pixel.x    ] +
  145.                                               0.7152 * modulation_map[4 * l_pixel.y * CONSTS.OUTPUT_IMG_WIDTH + 4 * l_pixel.x + 1] +
  146.                                               0.0722 * modulation_map[4 * l_pixel.y * CONSTS.OUTPUT_IMG_WIDTH + 4 * l_pixel.x + 2]);
  147.       }
  148.  
  149.       l_modulation = CONSTS.MODULATION_FORCE * l_inverted_lightness / 255;
  150.       l_outer_radius = l_radius + l_modulation + CONSTS.MODULATION_POS_OFFSET;
  151.       l_inner_radius = Math.max(0, l_radius - l_modulation - CONSTS.MODULATION_NEG_OFFSET);
  152.  
  153.       l_outer_pixel.x = parseInt(l_outer_radius * Math.sin(2 * Math.PI * (l_angle + angle) / 360) + CONSTS.OUTPUT_IMG_WIDTH / 2 + 1);
  154.       l_outer_pixel.y = parseInt(l_outer_radius * Math.cos(2 * Math.PI * (l_angle + angle) / 360) + CONSTS.OUTPUT_IMG_HEIGHT / 2 + 1);
  155.  
  156.       l_inner_pixel.x = parseInt(l_inner_radius * Math.sin(2 * Math.PI * (l_angle + angle) / 360) + CONSTS.OUTPUT_IMG_WIDTH / 2 + 1);
  157.       l_inner_pixel.y = parseInt(l_inner_radius * Math.cos(2 * Math.PI * (l_angle + angle) / 360) + CONSTS.OUTPUT_IMG_HEIGHT / 2 + 1);
  158.  
  159.       if(0 === l_rotation &&
  160.          0 === l_angle){
  161.         if(outer_spiral_start.is_position_empty()){
  162.           outer_spiral_start.copy(l_outer_pixel);
  163.         }
  164.  
  165.         l_old_outer_pixel.copy(outer_spiral_start);
  166.       }
  167.  
  168.       draw_line(l_inner_pixel, l_old_inner_pixel, output_map);
  169.       draw_line(l_outer_pixel, l_old_outer_pixel, output_map);
  170.  
  171.       l_old_inner_pixel.copy(l_inner_pixel);
  172.       l_old_outer_pixel.copy(l_outer_pixel);
  173.     }
  174.   }
  175.  
  176.   draw_line(l_outer_pixel, l_inner_pixel, output_map);
  177.  
  178.   return outer_spiral_start;
  179. }
  180.  
  181. function progress(status){
  182.   console.log(status);
  183.   document.getElementById('image_upload').classList.add('hidden');
  184.  
  185.   if(status < 0){
  186.     document.getElementById('progress').innerText = ':(';
  187.     document.body.style.backgroundColor = '#b93636';
  188.   }
  189.   else if(status < 100){
  190.     document.getElementById('progress').innerText = status + Math.floor(Math.random() * 5) + '%';
  191.   }
  192.   else{
  193.     document.getElementById('progress').innerText = '✓';
  194.     document.body.style.backgroundColor = '#36b93f';
  195.   }
  196.  
  197.   return new Promise(resolve => {
  198.     setTimeout(() => {
  199.       resolve();
  200.     }, 50);
  201.   });
  202. }
  203.  
  204. async function process_img(ctx, input_img, file, url){
  205.   if(0 === input_img.width || 0 === input_img.height){
  206.     console.warn('Invalid picture dimensions');
  207.     progress(-1);
  208.     return;
  209.   }
  210.  
  211.   var l_input_img_width = 0;
  212.   var l_input_img_height = 0;
  213.   var l_start_x = 0;
  214.   var l_start_y = 0;
  215.  
  216.   if(input_img.width < input_img.height){
  217.     l_input_img_width = parseInt(CONSTS.OUTPUT_IMG_WIDTH * input_img.width / input_img.height);
  218.     l_input_img_height = CONSTS.OUTPUT_IMG_HEIGHT;
  219.  
  220.     l_start_x = parseInt((CONSTS.OUTPUT_IMG_WIDTH - l_input_img_width) / 2);
  221.     l_start_y = 0;
  222.   }
  223.   else{
  224.     l_input_img_width = CONSTS.OUTPUT_IMG_WIDTH;
  225.     l_input_img_height = parseInt(CONSTS.OUTPUT_IMG_HEIGHT * input_img.height / input_img.width);
  226.  
  227.     l_start_x = 0;
  228.     l_start_y = parseInt((CONSTS.OUTPUT_IMG_HEIGHT - l_input_img_height) / 2);
  229.   }
  230.  
  231.   ctx.canvas.width = CONSTS.OUTPUT_IMG_WIDTH;
  232.   ctx.canvas.height = CONSTS.OUTPUT_IMG_HEIGHT;
  233.  
  234.   await progress(10);
  235.  
  236.   ctx.filter = 'drop-shadow(0 0 5px white) blur(3px)';
  237.  
  238.   await progress(50);
  239.  
  240.   ctx.drawImage(input_img, l_start_x, l_start_y, l_input_img_width, l_input_img_height);
  241.   var l_image_data = ctx.getImageData(0, 0, CONSTS.OUTPUT_IMG_WIDTH, CONSTS.OUTPUT_IMG_HEIGHT);
  242.  
  243.   var l_outer_spiral_start = new Position();
  244.   var l_output = ctx.createImageData(CONSTS.OUTPUT_IMG_WIDTH, CONSTS.OUTPUT_IMG_HEIGHT);
  245.  
  246.   await progress(70);
  247.  
  248.   l_outer_spiral_start = create_spiral_pair(l_image_data.data, 0, l_output.data, l_outer_spiral_start);
  249.   l_outer_spiral_start = create_spiral_pair(l_image_data.data, 180, l_output.data, l_outer_spiral_start);
  250.  
  251.   await progress(90);
  252.  
  253.   ctx.putImageData(l_output, 0, 0);
  254.   url.revokeObjectURL(input_img.src);
  255.  
  256.   await progress(100);
  257.   console.timeEnd();
  258.  
  259.   var l_link = document.createElement('a');
  260.   l_link.download = file.name.split('.').slice(0, -1).join('.') + '_spiro.png';
  261.   l_link.href = document.getElementById('canvas').toDataURL();
  262.   l_link.click();
  263. }
  264.  
  265. function main(){
  266.   console.log('Start');
  267.   console.time();
  268.  
  269.   var l_ctx = document.getElementById('canvas').getContext('2d');
  270.   var l_file = document.getElementById('uploadimage').files[0];
  271.   var l_url = window.URL || window.webkitURL;
  272.  
  273.   var l_input_img = new Image();
  274.   l_input_img.src = l_url.createObjectURL(l_file);
  275.  
  276.   l_input_img.onload = function(){
  277.     process_img(l_ctx, l_input_img, l_file, l_url);
  278.   };
  279.  
  280.   l_input_img.onerror = function(){
  281.     console.warn('Error on picture load');
  282.     progress(-1);
  283.   };
  284. }
  285.  
  286. document.addEventListener('DOMContentLoaded', function(){
  287.   document.getElementById('uploadimage').addEventListener('change', main, false);
  288. });
  289.  
  290. if('serviceWorker' in navigator){
  291.   navigator.serviceWorker.register('service_worker.js')
  292.   .then(function(registration){
  293.     console.log('Registration successful, scope is:', registration.scope);
  294.   })
  295.   .catch(function(error){
  296.     console.log('Service worker registration failed, error:', error);
  297.   });
  298. }
  299.  
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement