codify-node
Version:
Generates 1D, 2D, and composite barcodes in png, svg, or eps formats.
119 lines (104 loc) • 2.83 kB
text/typescript
import { PNG } from 'pngjs'
import RGBAColor from '../types/RGBAColor'
/**
* Renders a PNG Blob stream to a base64 PNG.
*
* @param {PNG} png
* @returns {Promise<string>} base64 representation
*/
function blobToBase64 (png: PNG): Promise<string> {
const chunks: Uint8Array[] = []
return new Promise((resolve) => {
png.pack()
png.on('data', (c: Uint8Array) => chunks.push(c))
png.on('end', () => {
const result = Buffer.concat(chunks)
resolve('data:image/png;base64,' + result.toString('base64'))
})
})
}
/**
* Writes the PNG instance to a buffer.
*
* @param {PNG} png - image instance
* @returns {string}
*/
function getBuffer (png: PNG): Buffer {
return PNG.sync.write(png)
}
/**
* Converts the given hexadecimal number to RGBA.
*
* @param {string} hex - 6-digit or 8-digit RGB(A) representation in hex
* @returns {RGBAColor} RGBA
*/
function getRgbaColor (hex = '000000FF'): RGBAColor {
const colors = [
...hex.match(/^([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})?$/i) ?? []
]
const alpha = parseInt(colors[4], 16)
if (colors.length >= 3) {
return {
red: parseInt(colors[1], 16),
green: parseInt(colors[2], 16),
blue: parseInt(colors[3], 16),
alpha: !isNaN(alpha) ? alpha : 255
}
}
// default to solid black if color is invalid
return {
red: 0,
green: 0,
blue: 0,
alpha: 255
}
}
/**
* Returns true if two RGB colors are equal.
*
* @param {RGBAColor} a
* @param {RGBAColor} b
* @returns {boolean}
*/
function isEqualColor (a: RGBAColor, b: RGBAColor): boolean {
return a.red === b.red && a.green === b.green && a.blue === b.blue
}
/**
* Renders RGB 24 bitmap into an image instance of PNG
*
* @param {number[]} bitmap - containing RGB values
* @param {number} width - width of bitmap
* @param {number} height height of bitmap
* @returns {PNG} instance of PNG
*/
function render (bitmap: number[], width: number, height: number, backgroundColor?: string, foregroundColor?: string): PNG {
const png = new PNG({ width, height })
const backgroundColorRgba = getRgbaColor(backgroundColor)
const foregroundColorRgba = getRgbaColor(foregroundColor)
let i = 0
for (let y = 0; y < height; y++) {
for (let x = 0; x < width; x++) {
const color: RGBAColor = {
red: bitmap[i],
green: bitmap[i + 1],
blue: bitmap[i + 2]
}
const rgba = isEqualColor(color, backgroundColorRgba)
? backgroundColorRgba
: foregroundColorRgba
const pos = (png.width * y + x) << 2
png.data[pos] = rgba.red
png.data[pos + 1] = rgba.green
png.data[pos + 2] = rgba.blue
png.data[pos + 3] = rgba.alpha || 0
i += 3
}
}
return png
}
export default {
blobToBase64,
getBuffer,
getRgbaColor,
render
}