Comparing version 1.0.7 to 1.1.0
217
lib/tti.js
@@ -5,108 +5,153 @@ require('colors'); | ||
const Jimp = require('jimp'); | ||
const config = require('./config'); | ||
const clp = require('./clp'); | ||
console.log(`${'i'.cyan} TTI by zephyr`); | ||
/** | ||
* Functions and variables. | ||
*/ | ||
console.log(`${'i'.cyan} TTI by zephyr`); | ||
const perfectWidth = pixelsCount => { | ||
let width = Math.ceil(Math.sqrt(pixelsCount)); | ||
while (1) { | ||
if (!(pixelsCount % width)) { | ||
return width; | ||
} | ||
width--; | ||
} | ||
} | ||
const argumentsParser = argv => { | ||
let raw = argv.slice(2); | ||
if (!raw.length) return {}; | ||
let argumentsMap = {}; | ||
for (let i = 0; i < raw.length; i++) { | ||
let alias = raw[i]; | ||
if (alias.startsWith('--')) { | ||
alias = alias.substring(2); | ||
let value = raw[i + 1]; | ||
if (value) { | ||
if (value.startsWith('--')) { | ||
argumentsMap[alias] = true; | ||
continue; | ||
} | ||
argumentsMap[alias] = value; | ||
i += 1; | ||
} else { | ||
argumentsMap[alias] = true; | ||
continue; | ||
} | ||
const cl = clp(config.parserConfig); | ||
const encode = (text, output) => { | ||
/** | ||
* Text processing. | ||
*/ | ||
const symbols = text.split('').map(s => { | ||
let code = s.charCodeAt(); | ||
return code < 20 ? '00' : code.toString(16); | ||
}); | ||
const pixels = _.chunk(symbols, 3).map(p => { | ||
if (p.length === 1) { | ||
return p.join('') + '0000ff'; | ||
} else if (p.length === 2) { | ||
return p.join('') + '00ff'; | ||
} else { | ||
console.log(`❌ Please, use -- prefix for arguments.`); | ||
process.exit(1); | ||
return p.join('') + 'ff'; | ||
} | ||
}); | ||
console.log('✔️ Text processed'); | ||
/** | ||
* Matrix configuration. | ||
*/ | ||
const pixelsCount = pixels.length; | ||
const areaRoot = Math.sqrt(pixelsCount); | ||
let width, height; | ||
if (pixelsCount != 3) { | ||
width = cl.flags.l || cl.flags.long ? pixelsCount : perfectWidth(pixelsCount); | ||
height = cl.flags.l || cl.flags.long ? 1 : pixelsCount / width; | ||
} else { | ||
width = cl.flags.l || cl.flags.long ? 3 : 2; | ||
height = cl.flags.l || cl.flags.long ? 1 : 2; | ||
} | ||
return argumentsMap; | ||
const matrix = _.chunk(pixels, width); | ||
/** | ||
* Image creation. | ||
*/ | ||
const image = new Jimp(width, height, '#000000ff'); | ||
matrix.forEach((row, y) => { | ||
row.forEach((pixel, x) => { | ||
image.setPixelColor(parseInt(pixel, 16), x, y); | ||
}); | ||
}); | ||
console.log('✔️ Matrix applied'); | ||
/** | ||
* Saving new image. | ||
*/ | ||
image.write(output, () => { | ||
console.log(`✔️ Done! (${pixels.length} pixels from ${symbols.length} symbols)`); | ||
}); | ||
} | ||
const config = argumentsParser(process.argv); | ||
const decode = async (image, output) => { | ||
let symbols = []; | ||
/** | ||
* Help guide. | ||
*/ | ||
if (config.help || config.h) { | ||
console.log( | ||
'Usage: tti [ options ]\n\n\ | ||
Options:\n\ | ||
\t--f|--file - Input text file directory. (required)\n\ | ||
\t--o|--output - Output image file name.\n\ | ||
\t--l|--long - Wraps to single line of pixels.\n' | ||
); | ||
process.exit(0); | ||
/** | ||
* Image scan. | ||
*/ | ||
for (const { x, y } of image.scanIterator(0, 0, image.bitmap.width, image.bitmap.height)) { | ||
let color = await image.getPixelColor(x, y).toString(16).substring(0, 6); | ||
let bytes = [ | ||
color.slice(0, 2), | ||
color.slice(2, 4), | ||
color.slice(4, 6) | ||
]; | ||
symbols = symbols.concat(bytes); | ||
} | ||
console.log('✔️ Image scanned'); | ||
if (!cl.flags.hex) { | ||
symbols = symbols.filter(e => e != '00').map(byte => String.fromCharCode(parseInt(byte, 16))); | ||
console.log('✔️ Converted to text'); | ||
} | ||
await fs.writeFileSync(output, symbols.join('')); | ||
console.log(`✔️ Done! (${symbols.length} symbols from ${image.bitmap.width * image.bitmap.height} pixels)`); | ||
} | ||
/** | ||
* Input reading. | ||
* Errors log. | ||
*/ | ||
if (!config.f && !config.file) { | ||
console.log('❌ No text file directory specified.'); | ||
if (cl.errors.length) { | ||
cl.errors.forEach(error => { | ||
let errorMessage = '❌ '; | ||
if (error.missingValue) { | ||
errorMessage += `Missing value at flag "${error.missingValue}".`; | ||
} else if (error.valueIn) { | ||
errorMessage += `Flag "${error.valueIn}" does not takes values.`; | ||
} else if (error.unknownFlag) { | ||
errorMessage += `Unknown flag "${error.unknownFlag}".`; | ||
} else if (error.unknownArgument) { | ||
errorMessage += `Unknown argument "${error.unknownArgument}".`; | ||
} else if (error.missingArgument) { | ||
errorMessage += `Missing argument "${error.missingArgument}".`; | ||
} | ||
console.log(errorMessage); | ||
}); | ||
process.exit(1); | ||
} | ||
let text; | ||
try { | ||
text = fs.readFileSync(config.f || config.file).toString('ascii'); | ||
} catch { | ||
console.log('❌ File not found.'); | ||
/** | ||
* Help string. | ||
*/ | ||
if (cl.flags.h || cl.flags.help) { | ||
console.log(config.helpString); | ||
process.exit(1); | ||
} | ||
if (!text.length) { | ||
console.log('❌ File is empty.'); | ||
process.exit(1); | ||
} | ||
/** | ||
* Text processing. | ||
*/ | ||
const symbols = text.split('').map(s => s.charCodeAt().toString(16)); | ||
const pixels = _.chunk(symbols, 3).map(p => p.length < 3 ? p.join('') + '00ff' : p.join('') + 'ff'); | ||
console.log('✔️ Text processed'); | ||
/** | ||
* Matrix configuration. | ||
*/ | ||
const pixelsCount = pixels.length; | ||
const width = config.l || config.long ? pixelsCount : Math.floor(Math.sqrt(pixelsCount)); | ||
const height = config.l || config.long ? 1 : Math.ceil(Math.sqrt(pixelsCount)); | ||
const matrix = _.chunk(pixels, width); | ||
/** | ||
* Image creation. | ||
*/ | ||
const image = new Jimp(width, height, '#000000ff'); | ||
matrix.forEach((row, y) => { | ||
row.forEach((pixel, x) => { | ||
image.setPixelColor(parseInt(pixel, 16), x, y); | ||
}); | ||
}); | ||
console.log('✔️ Matrix applied'); | ||
/** | ||
* Saving new image. | ||
*/ | ||
image.write(config.o || config.output || 'output.png', () => { | ||
console.log(`✔️ Done! (${symbols.length} symbols, ${pixels.length} pixels)`); | ||
}); | ||
if (cl.module === 'encode') { | ||
if (fs.existsSync(cl.arguments.input)) { | ||
let text = fs.readFileSync(cl.arguments.input).toString(); | ||
if (!text.length) { | ||
console.log('❌ File is empty.'); | ||
} else { | ||
encode(text, cl.arguments.output || `${cl.arguments.input.split(/\./)[0]}.png`); | ||
} | ||
} else { | ||
console.log('❌ Input file does not found.'); | ||
} | ||
} else { | ||
if (fs.existsSync(cl.arguments.input)) { | ||
(async () => { | ||
let image = await Jimp.read(cl.arguments.input); | ||
console.log('✔️ Image loaded'); | ||
decode(image, cl.arguments.output || `${cl.arguments.input.split(/\./)[0]}.txt`); | ||
})(); | ||
} else { | ||
console.log('❌ Input file does not found.'); | ||
} | ||
} |
{ | ||
"name": "tti.js", | ||
"version": "1.0.7", | ||
"version": "1.1.0", | ||
"description": "Text to image conversion utility.", | ||
@@ -5,0 +5,0 @@ "main": "./lib/tti.js", |
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
Major refactor
Supply chain riskPackage has recently undergone a major refactor. It may be unstable or indicate significant internal changes. Use caution when updating to versions that include significant changes.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
9084
6
255
1