@realfavicongenerator/generate-favicon
Version:
Generate a favicon
115 lines (114 loc) • 5.05 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
exports.isLightColor = exports.numberAliasToNumber = exports.getCSSFilter = exports.isCSSFilterTransformation = exports.userBrightnessToCssFilter = exports.transformSvg = exports.innerImageTransform = exports.initTransformation = exports.IconTransformationType = void 0;
var IconTransformationType;
(function (IconTransformationType) {
IconTransformationType["None"] = "none";
IconTransformationType["Background"] = "background";
IconTransformationType["Brightness"] = "brightness";
IconTransformationType["Invert"] = "invert";
})(IconTransformationType || (exports.IconTransformationType = IconTransformationType = {}));
;
const initTransformation = (type, parameters = {}) => (Object.assign({}, {
type,
backgroundColor: 'white',
backgroundRadius: 0.0,
imageScale: 1.0,
brightness: 1.0
}, parameters));
exports.initTransformation = initTransformation;
/**
* @param iiWidth The inner image width
* @param iiHeight The inner image height
* @param imgSize The output image size (same width/height)
* @param iiScale The inner image scale
*/
const innerImageTransform = (iiWidth, iiHeight, imgSize, iiScale = 1.0) => {
const iiSize = imgSize * iiScale;
const scaleFactor = iiSize / Math.max(iiWidth, iiHeight);
return {
scaleX: scaleFactor,
scaleY: scaleFactor,
translateX: (imgSize - iiWidth) / 2,
translateY: (imgSize - iiHeight) / 2,
// Set origin to prevent SVG.js from computing it itself
// When it does so, it uses the bbox and not the actual image size
// See https://github.com/RealFaviconGenerator/realfavicongenerator/issues/506
originX: iiWidth / 2,
originY: iiHeight / 2,
};
};
exports.innerImageTransform = innerImageTransform;
const transformSvg = (image, transformation, imageAdapter, finalImageSize = 1000) => {
const s = imageAdapter.createSvg().size(finalImageSize, finalImageSize);
// Why a wrapper? Because we need to apply a clip to the image, and clip
// can only be applied to a group **when the SVG is use as a favicon by Chrome**.
// When the clip is applied to the overall <svg> element:
// - Opened as a regular fine by Chome: the clip is applied.
// - Used as a favicon by Chrome: the clip is wrongly applied and the favicon appears as empty.
const wrapper = s.group();
if (transformation.type === IconTransformationType.Background) {
const b = wrapper.rect(finalImageSize, finalImageSize);
b.fill(transformation.backgroundColor);
}
const container = wrapper.group();
container.svg(image.svg());
const t = (0, exports.innerImageTransform)((0, exports.numberAliasToNumber)(image.width()), (0, exports.numberAliasToNumber)(image.height()), finalImageSize, transformation.type === IconTransformationType.Background ? transformation.imageScale : 1.0);
container.transform(t);
if ((0, exports.isCSSFilterTransformation)(transformation.type)) {
container.attr('style', `filter: ${(0, exports.getCSSFilter)(transformation)}`);
}
if (transformation.type === IconTransformationType.Background) {
const clip = wrapper.clip();
const rm = clip.rect();
rm.x(0);
rm.y(0);
rm.width(finalImageSize);
rm.height(finalImageSize);
rm.radius(transformation.backgroundRadius * finalImageSize / 2);
wrapper.clipWith(clip);
}
return s;
};
exports.transformSvg = transformSvg;
const userBrightnessToCssFilter = (userBrightness) => ({
brightness: userBrightness,
contrast: userBrightness > 1.3
? 1.0 / (1.0 + ((userBrightness - 1.3) / 2))
: 1.0
});
exports.userBrightnessToCssFilter = userBrightnessToCssFilter;
const isCSSFilterTransformation = (type) => (type === IconTransformationType.Brightness || type === IconTransformationType.Invert);
exports.isCSSFilterTransformation = isCSSFilterTransformation;
const getCSSFilter = (transformation) => {
switch (transformation.type) {
case (IconTransformationType.Brightness):
const { brightness, contrast } = (0, exports.userBrightnessToCssFilter)(transformation.brightness);
return `contrast(${contrast}) brightness(${brightness})`;
case (IconTransformationType.Invert):
return 'invert(100%)';
default:
return 'none';
}
};
exports.getCSSFilter = getCSSFilter;
const numberAliasToNumber = (n) => {
if (typeof n === 'string') {
return parseInt(n);
}
else if (typeof n === 'number') {
return n;
}
else {
return n.value;
}
};
exports.numberAliasToNumber = numberAliasToNumber;
const isLightColor = (color) => {
const r = parseInt(color.substring(1, 3), 16);
const g = parseInt(color.substring(3, 5), 16);
const b = parseInt(color.substring(5, 7), 16);
const yiq = ((r * 299) + (g * 587) + (b * 114)) / 1000;
return yiq > 128;
};
exports.isLightColor = isLightColor;