UNPKG

@realfavicongenerator/generate-favicon

Version:
115 lines (114 loc) 5.05 kB
"use strict"; 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;