Skip to content

Instantly share code, notes, and snippets.

@YujiSODE
Created January 27, 2021 03:05
Show Gist options
  • Save YujiSODE/bf499e05e7ae2876a8e6d864a0402ca1 to your computer and use it in GitHub Desktop.
Save YujiSODE/bf499e05e7ae2876a8e6d864a0402ca1 to your computer and use it in GitHub Desktop.
Tool to investigate color frequency of a canvas element through debugging console.
/*consoleRGB
* consoleRGB.js
*===================================================================
* Copyright (c) 2021 Yuji SODE <yuji.sode@gmail.com>
*
* This software is released under the MIT License.
* See LICENSE or http://opensource.org/licenses/mit-license.php
*===================================================================
* Tool to investigate color frequency of a canvas element through debugging console.
*
* === Synopsis ===
* - `consoleRGB.raw(srcCanvasId);`
* - `consoleRGB.graph(srcCanvasId,p);`
* - `consoleRGB.table(srcCanvasId,p);`
* - `consoleRGB.getColors(srcCanvasId,rgbHex0?,rgbHex1, ... ,rgbHex15?);`
* - `consoleRGB.get(srcCanvasId,rgbHex0);`
*
* --- Parameters ---
* - `srcCanvasId`: id of target canvas element to scan
* - `p`: an optional positive value that is not greater than 1.0 (default value is 1.0)
* - `rgbHex0` to `rgbHex15`: rgb colors that are expressed in css hexadecimal notation ("#RRGGBB") to get result
*
* Raw data is returned by `consoleRGB.raw`.
* `consoleRGB.graph` returns the upper `p*100`% of sorted result in descending order in histogram.
* `consoleRGB.table` returns the upper `p*100`% of sorted result in descending order in table.
* Frequencies of selected (1 to 16) colors are returned by `consoleRGB.getColors`.
* A frequency of selected color is returned by `consoleRGB.get`.
*===================================================================
*/
//Tool to extract RGB values from canvas element
//
//it returns rgb color frequency in a JSON string
function consoleRGB(srcCanvasId){
// - srcCanvasId: id of target canvas element to scan
//===
//
var slf=window,srcCanvas=slf.document.getElementById(srcCanvasId),
w=srcCanvas.width,h=srcCanvas.height;
//
//=== script for worker ===
var scpt=[
/*== head part of eventlistener ==*/
"self.addEventListener('message',",
/*== dealing with pixel data ==*/
`(e)=>{var d=e.data.data,W=${w},H=${h},i=0,j=0,k=0,rgb='',R={},`,
'f=(v)=>v<16?`0${v.toString(16)}`:v.toString(16);',
/*
* ##################
* while(i<H){
* j=0;
* while(j<W){
* rgb=`#${f(d[k])}${f(d[k+1])}${f(d[k+2])}`;
* if(!R[rgb]){R[rgb]=+0;}
* R[rgb]+=1;
* j+=1;
* k+=4;
* }
* i+=1;
* }
* ##################
*/
"while(i<H){j=0;while(j<W){rgb=`#${f(d[k])}${f(d[k+1])}${f(d[k+2])}`;if(!R[rgb]){R[rgb]=+0;}R[rgb]+=1;j+=1;k+=4;}i+=1;}",
/*== return result ==*/
'self.postMessage(JSON.stringify(R));d=W=H=i=j=k=rgb=R=null;},',
/*== tail part of eventlistener ==*/
'true);'
].join('');
//
//=== generation of worker ===
//
var blob=new Blob([scpt],{type:'text/javascript'});
var objUrl=slf.URL.createObjectURL(blob);
var wk=new Worker(objUrl);
slf.URL.revokeObjectURL(objUrl);
blob=objUrl=null;
//========================================
//
var F=()=>{
var log=[];
wk.addEventListener('message',(e)=>{
log[0]=e.data;
//
wk.terminate();
srcCanvas=null;
},true);
//
wk.postMessage(srcCanvas.getContext('2d').getImageData(+0,+0,+w,+h));
//
return log;
};
//========================================
//
return F();
};
//
//raw data
consoleRGB.raw=async (srcCanvasId)=>{
// - srcCanvasId: id of target canvas element to scan
//===
var rgb=await consoleRGB(srcCanvasId);
//
setTimeout(()=>Promise.resolve(rgb).then((v)=>{
console.log('color:frequency\n',v[0]);return v;
}),2000);
};
//
//histogram
//returned values are the upper `p*100`% of sorted result in descending order
consoleRGB.graph=async (srcCanvasId,p)=>{
// - srcCanvasId: id of target canvas element to scan
// - p: an optional positive value that is not greater than 1.0 (default value is 1.0)
//===
var rgb=await consoleRGB(srcCanvasId);
//
p=!p?1.0:+p;
p=0<p?+p:1.0;
p=1<p?1.0:+p;
//
setTimeout(()=>Promise.resolve(rgb).then((v)=>{
//
let log='\n',Freqs=JSON.parse(v[0]),
kFreq=Object.keys(Freqs),
nKeys=kFreq.length,css=[],e='',i=0;
//###### limit ######
const _LIMIT=256;
//###################
//sort by values
kFreq.sort((a,b)=>Freqs[b]-Freqs[a]);
//
while(i<nKeys*p){
e=kFreq[i];
log+=nKeys*p<_LIMIT?`%c${e}%c:${'#'.repeat(Math.ceil(Math.log2(+Freqs[e])))}\n`:`${e}:${'#'.repeat(Math.ceil(Math.log2(+Freqs[e])))}\n`;
//
//css colors
if(nKeys*p<_LIMIT){
css.push(`background:${e};`);
css.push(`background:#0000;`);
}
//
i+=1;
}
//
if(nKeys*p<_LIMIT){
console.log(log,...css);
}else{
console.log(log);
}
return v;
}),2000);
};
//
//table
//returned values are the upper `p*100`% of sorted result in descending order
consoleRGB.table=async (srcCanvasId,p)=>{
// - srcCanvasId: id of target canvas element to scan
// - p: an optional positive value that is not greater than 1.0 (default value is 1.0)
//===
var rgb=await consoleRGB(srcCanvasId);
//
p=!p?1.0:+p;
p=0<p?+p:1.0;
p=1<p?1.0:+p;
//
setTimeout(()=>Promise.resolve(rgb).then((v)=>{
//
let log='\n|color|frequency|\n|---|---|\n',Freqs=JSON.parse(v[0]),
kFreq=Object.keys(Freqs),
nKeys=kFreq.length,css=[],e='',i=0;
//###### limit ######
const _LIMIT=256;
//###################
//sort by values
kFreq.sort((a,b)=>Freqs[b]-Freqs[a]);
//
while(i<nKeys*p){
e=kFreq[i];
log+=nKeys*p<_LIMIT?`|%c${e}%c|${Freqs[e]}|\n`:`|${e}|${Freqs[e]}|\n`;
//
//css colors
if(nKeys*p<_LIMIT){
css.push(`background:${e};`);
css.push(`background:#0000;`);
}
//
i+=1;
}
//
if(nKeys*p<_LIMIT){
console.log(log,...css);
}else{
console.log(log);
}
return v;
}),2000);
};
//
//frequencies of selected colors
//1 to 16 colors are available
consoleRGB.getColors=async (srcCanvasId,rgbHex0,rgbHex1,rgbHex2,rgbHex3,rgbHex4,rgbHex5,rgbHex6,rgbHex7,rgbHex8,rgbHex9,rgbHex10,rgbHex11,rgbHex12,rgbHex13,rgbHex14,rgbHex15)=>{
// - srcCanvasId: id of target canvas element to scan
// - rgbHex0 to rgbHex15: rgb colors that are expressed in css hexadecimal notation ("#RRGGBB") to get result
//===
var rgbArgs=[],rgb=await consoleRGB(srcCanvasId);
//
if(!!rgbHex0){rgbArgs.push(rgbHex0)};
if(!!rgbHex1){rgbArgs.push(rgbHex1)};
if(!!rgbHex2){rgbArgs.push(rgbHex2)};
if(!!rgbHex3){rgbArgs.push(rgbHex3)};
if(!!rgbHex4){rgbArgs.push(rgbHex4)};
if(!!rgbHex5){rgbArgs.push(rgbHex5)};
if(!!rgbHex6){rgbArgs.push(rgbHex6)};
if(!!rgbHex7){rgbArgs.push(rgbHex7)};
if(!!rgbHex8){rgbArgs.push(rgbHex8)};
if(!!rgbHex9){rgbArgs.push(rgbHex9)};
if(!!rgbHex10){rgbArgs.push(rgbHex10)};
if(!!rgbHex11){rgbArgs.push(rgbHex11)};
if(!!rgbHex12){rgbArgs.push(rgbHex12)};
if(!!rgbHex13){rgbArgs.push(rgbHex13)};
if(!!rgbHex14){rgbArgs.push(rgbHex14)};
if(!!rgbHex15){rgbArgs.push(rgbHex15)};
//
//when no rgb color is given
if(!rgbArgs.length){rgbArgs.push('no_data')};
//
setTimeout(()=>Promise.resolve(rgb).then((v)=>{
//
let log='\n|color|#|frequency|\n|---|---|---|\n',
Freqs=JSON.parse(v[0]),n=rgbArgs.length,css=[],e='',i=0;
//
while(i<n){
e=rgbArgs[i];
log+=`|${e}|%c#%c|${!Freqs[e]?0:Freqs[e]}|\n`;
//
//css colors
css.push(`background:${e};`);
css.push(`background:#0000;`);
//
i+=1;
}
console.log(log,...css);
//
return v;
}),2000);
};
//
//a frequency of selected color
consoleRGB.get=async (srcCanvasId,rgbHex0)=>{
// - srcCanvasId: id of target canvas element to scan
// - rgbHex0: rgb color that is expressed in css hexadecimal notation ("#RRGGBB") to get result
//===
consoleRGB.getColors(srcCanvasId,rgbHex0);
};
//===================================================================
/*
* *** LICENSE ***
* MIT License
*
* Copyright (c) 2021 Yuji Sode
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
@YujiSODE
Copy link
Author

Table

SS_consoleRGB_20210124_02

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment