paint-by-numbers

Relaxing paint-by-numbers game  https://p.ce9e.org/paint-by-numbers/
git clone https://git.ce9e.org/paint-by-numbers.git

commit
a0df863a92095836935e5e09c5d6322647a61557
parent
cea83841076d014fa7326c9da72dde9b307e036c
Author
Tobias Bengfort <tobias.bengfort@posteo.de>
Date
2023-02-13 05:48
refactor: loader module

Diffstat

A loader.js 82 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
M paint.js 85 +++----------------------------------------------------------

2 files changed, 86 insertions, 81 deletions


diff --git a/loader.js b/loader.js

@@ -0,0 +1,82 @@
   -1     1 var file2img = function(file) {
   -1     2     // FIXME: uses unsafe inline image
   -1     3     return new Promise((resolve, reject) => {
   -1     4         var img = new Image();
   -1     5         var url = URL.createObjectURL(file);
   -1     6 
   -1     7         img.onerror = err => {
   -1     8             URL.revokeObjectURL(url);
   -1     9             reject(err);
   -1    10         };
   -1    11         img.onload = () => {
   -1    12             URL.revokeObjectURL(url);
   -1    13             resolve(img);
   -1    14         };
   -1    15 
   -1    16         img.src = url;
   -1    17     });
   -1    18 };
   -1    19 
   -1    20 var img2data = function(img, width) {
   -1    21     var _canvas = document.createElement('canvas');
   -1    22     _canvas.width = width;
   -1    23     _canvas.height = Math.round(img.height / img.width * width);
   -1    24     var _ctx = _canvas.getContext('2d');
   -1    25     _ctx.drawImage(img, 0, 0, _canvas.width, _canvas.height);
   -1    26     return _ctx.getImageData(0, 0, _canvas.width, _canvas.height);
   -1    27 };
   -1    28 
   -1    29 var round = function(c) {
   -1    30     return Math.floor(c / 51) * 3;
   -1    31 };
   -1    32 
   -1    33 var makecolor = function(a) {
   -1    34     return '#'
   -1    35         + round(a[0]).toString(16)
   -1    36         + round(a[1]).toString(16)
   -1    37         + round(a[2]).toString(16);
   -1    38 };
   -1    39 
   -1    40 var sRGB = function(c) {
   -1    41     var x = round(c) / 15;
   -1    42     if (x < 0.04045) {
   -1    43         return x / 12.92;
   -1    44     } else {
   -1    45         return Math.pow((x + 0.055) / 1.055, 2.4);
   -1    46     }
   -1    47 };
   -1    48 
   -1    49 var makeContrast = function(a) {
   -1    50     var l = 0.2126 * sRGB(a[0]) + 0.7152 * sRGB(a[1]) + 0.0722 * sRGB(a[2]);
   -1    51     return l > 0.18 ? '#000' : '#fff';
   -1    52 };
   -1    53 
   -1    54 var analyze = function(img) {
   -1    55     var c, i, j;
   -1    56     var colors = ['white'];
   -1    57     var contrasts = ['black'];
   -1    58     var out = [];
   -1    59     for (i = 0; i < img.data.length; i += 4) {
   -1    60         c = makecolor(img.data.slice(i, i + 3));
   -1    61         j = colors.indexOf(c);
   -1    62         if (j === -1) {
   -1    63             j = colors.length;
   -1    64             colors.push(c);
   -1    65             contrasts.push(makeContrast(img.data.slice(i, i + 3)));
   -1    66         }
   -1    67         out.push(j);
   -1    68     }
   -1    69     return {
   -1    70         width: img.width,
   -1    71         height: img.height,
   -1    72         colors: colors,
   -1    73         contrasts: contrasts,
   -1    74         data: out,
   -1    75     };
   -1    76 };
   -1    77 
   -1    78 export var loadImage = function(input, width) {
   -1    79     return file2img(input.files[0]).then(img => {
   -1    80         return analyze(img2data(img, width));
   -1    81     });
   -1    82 };

diff --git a/paint.js b/paint.js

@@ -1,5 +1,6 @@
    1     1 import { Frame, PXSIZE } from './frame.js';
    2     2 import { View } from './view.js';
   -1     3 import { loadImage } from './loader.js';
    3     4 import * as utils from './utils.js';
    4     5 
    5     6 var input = document.querySelector('input');
@@ -16,88 +17,10 @@ var pencil = 0;
   16    17 var speed_x = 0;
   17    18 var speed_y = 0;
   18    19 
   19    -1 var round = function(c) {
   20    -1     return Math.floor(c / 51) * 3;
   21    -1 };
   22    -1 
   23    -1 var makecolor = function(a) {
   24    -1     return '#'
   25    -1         + round(a[0]).toString(16)
   26    -1         + round(a[1]).toString(16)
   27    -1         + round(a[2]).toString(16);
   28    -1 };
   29    -1 
   30    -1 var sRGB = function(c) {
   31    -1     var x = round(c) / 15;
   32    -1     if (x < 0.04045) {
   33    -1         return x / 12.92;
   34    -1     } else {
   35    -1         return Math.pow((x + 0.055) / 1.055, 2.4);
   36    -1     }
   37    -1 };
   38    -1 
   39    -1 var makeContrast = function(a) {
   40    -1     var l = 0.2126 * sRGB(a[0]) + 0.7152 * sRGB(a[1]) + 0.0722 * sRGB(a[2]);
   41    -1     return l > 0.18 ? '#000' : '#fff';
   42    -1 };
   43    -1 
   44    -1 var file2img = function(file) {
   45    -1     return new Promise((resolve, reject) => {
   46    -1         var img = new Image();
   47    -1         var url = URL.createObjectURL(file);
   48    -1 
   49    -1         img.onerror = err => {
   50    -1             URL.revokeObjectURL(url);
   51    -1             reject(err);
   52    -1         };
   53    -1         img.onload = () => {
   54    -1             URL.revokeObjectURL(url);
   55    -1             resolve(img);
   56    -1         };
   57    -1 
   58    -1         img.src = url;
   59    -1     });
   60    -1 };
   61    -1 
   62    -1 var img2data = function(img, scale) {
   63    -1     var _canvas = document.createElement('canvas');
   64    -1     _canvas.height = Math.round(img.height * scale);
   65    -1     _canvas.width = Math.round(img.width * scale);
   66    -1     var _ctx = _canvas.getContext('2d');
   67    -1     _ctx.drawImage(img, 0, 0, _canvas.width, _canvas.height);
   68    -1     return _ctx.getImageData(0, 0, _canvas.width, _canvas.height);
   69    -1 };
   70    -1 
   71    -1 var analyze = function(img) {
   72    -1     var c, i, j;
   73    -1     var colors = ['white'];
   74    -1     var contrasts = ['black'];
   75    -1     var out = [];
   76    -1     for (i = 0; i < img.data.length; i += 4) {
   77    -1         c = makecolor(img.data.slice(i, i + 3));
   78    -1         j = colors.indexOf(c);
   79    -1         if (j === -1) {
   80    -1             j = colors.length;
   81    -1             colors.push(c);
   82    -1             contrasts.push(makeContrast(img.data.slice(i, i + 3)));
   83    -1         }
   84    -1         out.push(j);
   85    -1     }
   86    -1     return {
   87    -1         width: img.width,
   88    -1         height: img.height,
   89    -1         colors: colors,
   90    -1         contrasts: contrasts,
   91    -1         data: out,
   92    -1     };
   93    -1 };
   94    -1 
   95    20 input.addEventListener('change', () => {
   96    -1     file2img(input.files[0]).then(img => {
   97    -1         // FIXME: configurable size
   98    -1         data = analyze(img2data(img, 80 / img.width));
   99    -1 
  100    -1         frame.setImage(data);
   -1    21     // FIXME: configurable size
   -1    22     loadImage(input, 80).then(image => {
   -1    23         frame.setImage(image);
  101    24 
  102    25         palette.innerHTML = '';
  103    26         for (var i = 0; i < data.colors.length; i++) {