How to find missing font glyphs using node canvas? - node.js

I am trying to find missing glyphs with node canvas by comparing the rendered glyph with a known missing glyph, but it's not working. Any ideas?
const { createCanvas, loadImage } = require('canvas')
const fs = require('fs')
const testCanvas = createCanvas(200, 200)
const referenceCanvas = createCanvas(200, 200)
const ctxTest = testCanvas.getContext('2d')
const ctxRef = referenceCanvas.getContext('2d')
ctxRef.fillText('𠆼', 0, 0)
const refData = ctxRef.getImageData(0, 0, referenceCanvas.width, referenceCanvas.height).data.join('')
fs.readFileSync('path-to-chars.txt', 'utf-8').trim()
.split(/\n+/)
.filter(x => x.startsWith('U+'))
.map(x => {
let [a, b, c] = x.split(/\t/)
let q = String.fromCodePoint(parseInt(a.replace('U+', ''), 16))
if (test(q)) {
console.log('skip', a, q)
return
}
c.match(/\^([^\$]+)\$/)
const fullText = RegExp.$1
const radicals = [...fullText.replace(/[⿰⿱⿲⿳⿴⿵⿶⿷⿸⿹⿺⿻]/g, '').replace(/\{[^\}]+\}/g, '')]
for (let i = 0, n = radicals.length; i < n; i++) {
const char = radicals[i]
if (test(char)) return
}
console.log(radicals, radicals.map(x => x.codePointAt(0).toString(16)))
return q
})
function test(char) {
ctxTest.clearRect(0, 0, testCanvas.width, testCanvas.height)
ctxTest.fillText(char, 0, 0)
const testData = ctxTest.getImageData(0, 0, testCanvas.width, testCanvas.height).data.join('')
console.log(char, testData === refData)
return testData === refData
}
I don't know what ones are missing in advance. I am just trying to filter them out.

Related

Button labels going wrong on pdf-lib capture using html2canvas

I am using pdf-lib to capture and html2canvas, but when the page is captured, Button labels, they go wrong. "Buy Again" becomes "BuyA Gain".
Also when I scroll the page, the page captured gets cut, when it should not because it is being captured on the basis of elementID
const onClickPrint = () => {
const domElement = document.getElementById(elementId);
var printButton = document.getElementById("printIcon");
printButton.style.visibility = "hidden";
var downloadButton;
try {
downloadButton = document.getElementById("downloadIcon");
downloadButton.style.visibility = "hidden";
} catch (e) { }
html2canvas(domElement).then((canvas) => {
(async () => {
const pdfDoc = await PDFDocument.create();
const imagePDF = await pdfDoc.embedPng(canvas.toDataURL("image/PNG"));
let height = imagePDF.height;
let width = imagePDF.width;
const page = pdfDoc.addPage([A4_PAGE.width, A4_PAGE.height]);
let widthRatio = A4_PAGE.width / width;
let heightRatio = A4_PAGE.height / height;
let ratio = widthRatio > heightRatio ? heightRatio : widthRatio;
page.drawImage(imagePDF, {
x: A4_PAGE.width / 2 - (width * ratio) / 2,
y: A4_PAGE.height / 2 - (height * ratio) / 2,
width: width * ratio,
height: height * ratio,
});
const pdfBytes = await pdfDoc.save();
const blob = new Blob([pdfBytes], { type: "application/pdf" });
openPrintDialog(blob);
})();
});
printButton.style.visibility = "visible";
if (downloadButton != null) {
downloadButton.style.visibility = "visible";
}
};

how to read json file and search with filter for common items in nodejs

I have JSON file contain games objects, I want to get top 5 games that have the highest total playtime between users.
I tried to get all objects by reading the file using file system in nodejs :
const queryGames = async () => {
let data = fs.readFileSync(path.resolve(__dirname, '../../games.json'))
let games = JSON.parse(data)
return games
}
/**
* Query for top games by play time
* #returns {Promise<QueryResult>}
*/
const selectTopByPlaytime = async () => {
}
this is the json file : https://jsoneditoronline.org/#left=cloud.3b82169327044c04b7207fa186aee85b&right=local.tiniqu
something like this should work.
const gamePlayData = require('./gamePlay.json').data
/**
* Query for games and time
* #returns {
'League of legends': 1650,
'World of warcraft': 2300,
'Dark Souls': 218,
'The Witcher 3: Wild Hunt': 987,
etc....
}
*/
const getGamePlayTimes = () => {
gamePlayTimes = {}
gamePlayData.forEach( (playData) => {
const gameName = playData.game
if(gamePlayTimes[gameName]) {
gamePlayTimes[gameName] += playData.playTime
}
else {
gamePlayTimes[gameName] = playData.playTime
}
})
return gamePlayTimes;
}
const getGamesAndTimesAsList = (playTimes) => {
let gamesWithTimeArr = [];
let i = 0;
for(let game in playTimes) {
let gameAndPlayTime = {game: "", playTime: 0};
gameAndPlayTime.game = game;
gameAndPlayTime.playTime = playTimes[game];
gamesWithTimeArr[i++] = gameAndPlayTime
}
return gamesWithTimeArr;
}
const reverseBubbleSort = (a, par) => {
let swapped;
do {
swapped = false;
for (var i = 0; i < a.length - 1; i++) {
if (a[i][par] < a[i + 1][par]) {
var temp = a[i];
a[i] = a[i + 1];
a[i + 1] = temp;
swapped = true;
}
}
} while (swapped);
return a;
}
sortedArr = reverseBubbleSort(getGamesAndTimesAsList( getGameAndPlayTimes() ) , 'playTime')
const top5 = sortedArr.slice(0, 5);
console.log(top5);

.push is not a function in web crawler

I am writing a node JS web crawler class, and I have encountered the following error, this.textInvertedIndex[word].push is not a function. Upon further inspection I realised that for some reason this.textInvertedIndex[word] was written as a native object, function Object({ [native code] }). For the first few iterations, by console logging this.textInvertedIndex everything seemed fine as it was an object of arrays. But then suddenly this error occurred. Is there any part of the code where I am implicitly rewriting textInvertedIndex?
Here is the relevant class:
function Crawler(queue, maxIndexSize) {
this.queue = queue;
this.maxIndexSize = maxIndexSize;
this.findChunks = () => {
let currentChunk;
let minimumDistance = Infinity;
for (i = 1; i <= this.maxIndexSize; i++) {
if (this.maxIndexSize % i === 0) {
const newDistance = Math.abs(i - 30);
if (newDistance < minimumDistance) {
minimumDistance = newDistance;
currentChunk = i;
} else {
return currentChunk
};
};
};
};
this.chunks = this.findChunks();
this.chunkSize = this.maxIndexSize / this.chunks;
this.totalWordOccurances = {};
this.imageInvertedIndex = {};
this.textInvertedIndex = {};
this.images = [];
this.sites = [];
this.seen = {};
this.write = (url, html) => {
const documentId = this.sites.length;
const website = new Website(url, html);
const title = website.title();
const content = website.content(title);
const words = content.filter(item => typeof item !== "object");
const wordsLength = words.length;
const query = new Query(words);
const individualWords = query.individualize(words);
this.seen[url] = true;
this.sites.push({
url,
title,
description: website.description()
});
for (word of individualWords) {
const normalizedTf = query.count(word) / wordsLength;
const textInvertedIndexEntry = {
documentId,
normalizedTf
};
if (this.textInvertedIndex[word]) {
this.textInvertedIndex[word].push(textInvertedIndexEntry);
} else {
this.textInvertedIndex[word] = [textInvertedIndexEntry];
};
if (this.totalWordOccurances[word]) {
this.totalWordOccurances[word] += 1;
} else {
this.totalWordOccurances[word] = 1;
};
};
for (i = 0; i < content.length; i++) {
const item = content[i];
if (typeof item === "object") {
const imageId = this.images.length;
this.images.push(item);
for (word of individualWords) {
const imageScore = getImageScore(i, word, content);
const imageInvertedIndexEntry = {
imageId,
imageScore
};
if (this.imageInvertedIndex[word]) {
this.imageInvertedIndex[word].push(imageInvertedIndexEntry);
} else {
this.imageInvertedIndex[word] = [imageInvertedIndexEntry];
};
};
};
};
};
this.crawl = async () => {
while (this.sites.length !== this.maxIndexSize) {
let nextQueue = [];
const websitesUnfiltered = await Promise.all(this.queue.map((url) => {
const website = new Website(url);
return website.request();
}));
const websitesToAdd = this.maxIndexSize - this.sites.length;
let websites = websitesUnfiltered.filter(message => message !== "Failure")
.slice(0, websitesToAdd);
for (site of websites) {
const url = site.url;
const htmlCode = site.htmlCode;
const website = new Website(url, htmlCode);
this.write(url, htmlCode);
nextQueue = nextQueue.concat(website.urls());
};
nextQueue = new Query(nextQueue.filter(url => !this.seen[url]))
.individualize();
this.queue = nextQueue;
};
};
};
Called like this
const crawler = new Crawler(["https://stanford.edu/"], 25000000);
crawler.crawl();
this.textInvertedIndex = {}; is defining an Object of which push is not a valid function. you can change it to an array by defining it as this.textInvertedIndex = []; otherwise you can add key/value entries to the object as it is defined like this: this.textInvertedIndex[key] = value;
Turns out, my key was accessing this.textInvertedIndex[word]. And word was constructor. constructor is already a built in object property so it can never be rewritten as an array with .push defined. To solve this problem, make all object keys capital, so constructor will become CONSTRUCTOR, thus making sure that already existing object properties are never called.

How can simplify node script

The code is:
const _ = require('lodash');
const output = [];
let i = 0;
const inputString = "/h1/h2/h3/h4";
_.forEach(inputString.split('/').filter(e => e), (f, key, res) => {
if (i < res.length - 1 ) {
output.push(`/${_.slice(res, 0, i += 1).join('/')}`);
}
});
console.log(output);
The expect output is array and skip last one : ['/h1', '/h1/h2' , '/h1/h2/h3']
How can i simplify it ? Thanks a lot !
One option would be to split the string into the hs, slice off the empty string in the first position, and pop() the last. Then, .map the resulting array by joining indicies 0 to 0, then 0 to 1, then 0 to 2, etc:
const inputString = "/h1/h2/h3/h4";
const items = inputString.split('/').slice(1); // slice to remove empty string at [0]
items.pop(); // remove last item (h4)
const output = items.map((_, i) => '/' + items.slice(0, i + 1).join('/'));
console.log(output);
No external library required
As comment notes, another way would be to find all indicies of /:
const inputString = "/h1/h2/h3/h4";
const slashIndicies = [...inputString].reduce((a, char, i) => {
if (char === '/') a.push(i);
return a;
}, []);
// ignore first leading slash:
slashIndicies.shift();
const output = slashIndicies.map((slashIndex) => inputString.slice(0, slashIndex));
console.log(output);
As a variant:
'use strict';
const inputString = '/h1/h2/h3/h4';
const arr = [...inputString].reduce((acc, ch) => {
if (ch === '/') acc.push(`${acc[acc.length - 1] || ''}${ch}`);
else acc[acc.length - 1] += ch;
return acc;
}, []).slice(0, -1);
console.log(arr);

How to use fs.watchFile to reload Json File

I have couple functions that re-structure the JSON file. They write and manipulate one another. They are in the same js file. Every function depends on the function before to run properly. But since every one of them manipulates the file synchronously after reading it, I have encountered a problem which is hard to explain for me because I am not sure if I understand it well. When the first function finishes the task second function can't read it(It reads but can't see the updated object and its property). If I run all the functions one by one and restart the program afterward, it reads very well. Here is what I have tried until now;
I tried to make my functions asynchronous
I tried to use setTimeout function and give it up until 10 seconds
Both did not work for me. I read in StackOverflow that it fs.watch could help me but couldn't find a proper explanation of how to implement that. Any help regarding this issue I am having would be much appreciated.
-I know I can use another database but I just want to know this one because I am regularly using this. Please don't be rude if I am stupid :P
const fs = require('fs');
const ReadRawData= fs.readFileSync('Data.json');
const ReadParsed = JSON.parse(ReadRawData);
fs.watchFile('Data.json', (curr, prev) => {
console.log(`the current mtime is: ${curr.mtime}`);
console.log(`the previous mtime was: ${prev.mtime}`);
});
I just want to know how can I reload this ReadParsed everytime a file changed and can reach the reloaded version from functions.
Here is my full code; This is testing2.js
const request = require('request');
const cherio= require('cheerio');
const fs = require('fs');
const cheerioTableparser = require('cheerio-tableparser');
async function htmlCollector () {
const ReadTransactionBase = await fs.readFileSync('transactionDatabase.json');
const ReadTransaction = JSON.parse(ReadTransactionBase);
ReadTransaction.pageInformation = "";
let editedDataBase = JSON.stringify(ReadTransaction, null, 2);
fs.writeFileSync('transactionDatabase.json', editedDataBase);
for (let counter = 1; counter <= ReadTransaction.maxPage; counter++) {
request(ReadTransaction.link + counter,
(error, response, html) => {
if (!error && response.statusCode === 200) {
const $ = cherio.load(html);
const items = [];
$('#maindiv').each(function (i, elem) {
items[i] = $(this).html();
});
let newPage = {['PageNumber'+counter] : items};
ReadTransaction.pageInformation = Object.assign(newPage,ReadTransaction.pageInformation);
let editedDataBase = JSON.stringify(ReadTransaction, null, 2);
fs.writeFileSync('transactionDatabase.json', editedDataBase);
}
})
}
}
async function databaseModifier () {
const ReadTransactionBase = await fs.readFileSync('transactionDatabase.json');
const ReadTransaction = JSON.parse(ReadTransactionBase);
delete ReadTransaction.from;
delete ReadTransaction.quantities;
delete ReadTransaction.orangeBox;
let editedDataBase = JSON.stringify(ReadTransaction, null, 2);
console.log('test');
fs.writeFileSync('transactionDatabase.json', editedDataBase);
for (let i=1; i<=Object.keys(ReadTransaction.pageInformation).length;i++) {
let nums = 'PageNumber' + i;
let newObject = {[nums]: {}};
ReadTransaction.from = Object.assign(newObject,ReadTransaction.from);
ReadTransaction.orangeBox = Object.assign(newObject,ReadTransaction.orangeBox);
ReadTransaction.quantities = Object.assign(newObject,ReadTransaction.quantities);
let editedDataBase = JSON.stringify(ReadTransaction, null, 2);
fs.writeFileSync('transactionDatabase.json', editedDataBase);
}
}
async function fromOrangeBoxQuantities () {
const ReadTransactionBase = await fs.readFileSync('transactionDatabase.json');
const ReadTransaction = JSON.parse(ReadTransactionBase);
for (let counter = 1; counter <= ReadTransaction.maxPage ; counter++) {
let HTMLPageNumber = 'PageNumber' + counter;
let $ = cherio.load(ReadTransaction.pageInformation[HTMLPageNumber][0]);
cheerioTableparser($);
let data = $('.table').parsetable(true,true,true);
for (let sCounter = 1; sCounter <= data[2].length; sCounter++) {
let fromTable = {[sCounter] : [data[2][sCounter-1]]};
let orangeBoxTable = {[sCounter] : [data[3][sCounter-1]]};
let quantityTable = {[sCounter] : [data[5][sCounter-1]]};
ReadTransaction.from[HTMLPageNumber] = Object.assign(fromTable,ReadTransaction.from[HTMLPageNumber]);
ReadTransaction.orangeBox[HTMLPageNumber] = Object.assign(orangeBoxTable,ReadTransaction.orangeBox[HTMLPageNumber]);
ReadTransaction.quantities[HTMLPageNumber] = Object.assign(quantityTable,ReadTransaction.quantities[HTMLPageNumber]);
let editedDataBase = JSON.stringify(ReadTransaction, null, 2);
fs.writeFileSync('transactionDatabase.json', editedDataBase);
}
}
}
async function validatorOfTransactions (){
const ReadTransactionBase = await fs.readFileSync('transactionDatabase.json');
const ReadTransaction = JSON.parse(ReadTransactionBase);
ReadTransaction.validQuantities = [];
let editedDataBase = JSON.stringify(ReadTransaction, null, 2);
fs.writeFileSync('transactionDatabase.json', editedDataBase);
for (let counter = 1; counter <= ReadTransaction.maxPage ; counter++) {
let HTMLPageNumber = 'PageNumber' + counter;
let length = Object.keys(ReadTransaction.from[HTMLPageNumber]).length;
for (let sCounter = 1; sCounter <= length; sCounter++) {
let a = ReadTransaction.from[HTMLPageNumber][sCounter].toString();
let b = ReadTransaction.fromAddress;
let c = ReadTransaction.orangeBox[HTMLPageNumber][sCounter].toString();
let d = ReadTransaction.OrangeBox;
if (a === b && c === d) {
console.log('yay');
ReadTransaction.validQuantities.push(parseFloat(ReadTransaction.quantities[HTMLPageNumber][sCounter].toString().replace(/,/g,'')));
let editedDataBase = JSON.stringify(ReadTransaction, null, 2);
fs.writeFileSync('transactionDatabase.json', editedDataBase);
}
}
}
}
async function finalizeCalculation () {
const ReadTransactionBase = await fs.readFileSync('transactionDatabase.json');
const ReadTransaction = JSON.parse(ReadTransactionBase);
let NewArray = ReadTransaction.validQuantities;
return NewArray.reduce((a,b) => a +b, 0);
}
module.exports = {
htmlCollector : htmlCollector,
databaseModifier : databaseModifier,
fromOrangeBoxQuantities : fromOrangeBoxQuantities,
validatorOfTransactions : validatorOfTransactions,
finalizeCalculation : finalizeCalculation
};
This is transactionDatabase.json;
{
"link": "https://etherscan.io/token/generic-tokentxns2?contractAddress=0xaf2de5cb07d8f5de2369ff104150fef9dc0e604b&mode=&a=0x11209cbc2ea8cf829aa5aa1cdc5a4e5962e70655&p=",
"maxPage": 12,
"fromAddress": "0x11209cbc2ea8cf829aa5aa1cdc5a4e5962e70655",
"OrangeBox": "OUT",
"validQuantities": [],
"pageInformation": {}
}
this is newtest.js;
let testing2 = require('./testing2');
testing2.htmlCollector().then(() => testing2.databaseModifier().then(()=> testing2.fromOrangeBoxQuantities().then(()=> testing2.validatorOfTransactions().then())));
Here is the error I am getting;
(node:21760) UnhandledPromiseRejectionWarning: TypeError: Cannot read property '0' of undefined

Resources