123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152 |
- 'use strict';
- const collections = require('./_collections.js');
- exports.type = 'visitor';
- exports.name = 'convertColors';
- exports.active = true;
- exports.description = 'converts colors: rgb() to #rrggbb and #rrggbb to #rgb';
- const rNumber = '([+-]?(?:\\d*\\.\\d+|\\d+\\.?)%?)';
- const rComma = '\\s*,\\s*';
- const regRGB = new RegExp(
- '^rgb\\(\\s*' + rNumber + rComma + rNumber + rComma + rNumber + '\\s*\\)$'
- );
- const regHEX = /^#(([a-fA-F0-9])\2){3}$/;
- /**
- * Convert [r, g, b] to #rrggbb.
- *
- * @see https://gist.github.com/983535
- *
- * @example
- * rgb2hex([255, 255, 255]) // '#ffffff'
- *
- * @author Jed Schmidt
- *
- * @type {(rgb: Array<number>) => string}
- */
- const convertRgbToHex = ([r, g, b]) => {
- // combine the octets into a 32-bit integer as: [1][r][g][b]
- const hexNumber =
- // operator precedence is (+) > (<<) > (|)
- ((((256 + // [1][0]
- r) << // [1][r]
- 8) | // [1][r][0]
- g) << // [1][r][g]
- 8) | // [1][r][g][0]
- b;
- // serialize [1][r][g][b] to a hex string, and
- // remove the 1 to get the number with 0s intact
- return '#' + hexNumber.toString(16).slice(1).toUpperCase();
- };
- /**
- * Convert different colors formats in element attributes to hex.
- *
- * @see https://www.w3.org/TR/SVG11/types.html#DataTypeColor
- * @see https://www.w3.org/TR/SVG11/single-page.html#types-ColorKeywords
- *
- * @example
- * Convert color name keyword to long hex:
- * fuchsia ➡ #ff00ff
- *
- * Convert rgb() to long hex:
- * rgb(255, 0, 255) ➡ #ff00ff
- * rgb(50%, 100, 100%) ➡ #7f64ff
- *
- * Convert long hex to short hex:
- * #aabbcc ➡ #abc
- *
- * Convert hex to short name
- * #000080 ➡ navy
- *
- * @author Kir Belevich
- *
- * @type {import('../lib/types').Plugin<{
- * currentColor?: boolean | string | RegExp,
- * names2hex?: boolean,
- * rgb2hex?: boolean,
- * shorthex?: boolean,
- * shortname?: boolean,
- * }>}
- */
- exports.fn = (_root, params) => {
- const {
- currentColor = false,
- names2hex = true,
- rgb2hex = true,
- shorthex = true,
- shortname = true,
- } = params;
- return {
- element: {
- enter: (node) => {
- for (const [name, value] of Object.entries(node.attributes)) {
- if (collections.colorsProps.includes(name)) {
- let val = value;
- // convert colors to currentColor
- if (currentColor) {
- let matched;
- if (typeof currentColor === 'string') {
- matched = val === currentColor;
- } else if (currentColor instanceof RegExp) {
- matched = currentColor.exec(val) != null;
- } else {
- matched = val !== 'none';
- }
- if (matched) {
- val = 'currentColor';
- }
- }
- // convert color name keyword to long hex
- if (names2hex) {
- const colorName = val.toLowerCase();
- if (collections.colorsNames[colorName] != null) {
- val = collections.colorsNames[colorName];
- }
- }
- // convert rgb() to long hex
- if (rgb2hex) {
- let match = val.match(regRGB);
- if (match != null) {
- let nums = match.slice(1, 4).map((m) => {
- let n;
- if (m.indexOf('%') > -1) {
- n = Math.round(parseFloat(m) * 2.55);
- } else {
- n = Number(m);
- }
- return Math.max(0, Math.min(n, 255));
- });
- val = convertRgbToHex(nums);
- }
- }
- // convert long hex to short hex
- if (shorthex) {
- let match = val.match(regHEX);
- if (match != null) {
- val = '#' + match[0][1] + match[0][3] + match[0][5];
- }
- }
- // convert hex to short name
- if (shortname) {
- const colorName = val.toLowerCase();
- if (collections.colorsShortNames[colorName] != null) {
- val = collections.colorsShortNames[colorName];
- }
- }
- node.attributes[name] = val;
- }
- }
- },
- },
- };
- };
|