Skip to content

Commit

Permalink
Обработка входящих изображений
Browse files Browse the repository at this point in the history
  • Loading branch information
efiand committed Nov 23, 2024
1 parent 8365ef9 commit b49c9ae
Show file tree
Hide file tree
Showing 9 changed files with 295 additions and 3 deletions.
5 changes: 5 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,11 @@ dist
node_modules
yarn.lock

# Temp
raw/*
!raw/icons/README.md
!raw/images/README.md

# Editor directories and files
*.njsproj
*.ntvs*
Expand Down
2 changes: 1 addition & 1 deletion eslint.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ export default [
vue: pluginVue,
},
rules: {
"no-console": [strictMode ? "warn" : "off", { allow: ["error"] }],
"no-console": [strictMode ? "warn" : "off", { allow: ["error", "info"] }],
"no-debugger": strictMode ? "warn" : "off",
"vue/component-name-in-template-casing": [
"error",
Expand Down
145 changes: 145 additions & 0 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 2 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
"eslint-gitignore": "0.1.0",
"eslint-plugin-perfectionist": "3.9.1",
"eslint-plugin-vue": "9.30.0",
"imagescript": "1.3.0",
"pixelperfect-tool": "1.9.2",
"postcss": "8.4.47",
"postcss-html": "1.7.0",
Expand All @@ -37,6 +38,7 @@
"stylelint": "16.10.0",
"stylelint-config-standard": "36.0.1",
"stylelint-order": "6.0.4",
"svgo": "3.3.2",
"twig": "1.17.1",
"vite": "5.4.10",
"vite-plugin-minify": "2.0.1"
Expand Down
2 changes: 1 addition & 1 deletion public/images/README.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
<!-- @format -->

Папка для контентных изображений.
Папка для контентных изображений. Сюда автоматически попадают изображения из папки `raw/images`.
2 changes: 1 addition & 1 deletion src/icons/README.md
Original file line number Diff line number Diff line change
@@ -1 +1 @@
Папка для SVG-иконок, встраиваемых в CSS.
Папка для SVG-иконок, встраиваемых в CSS. Сюда автоматически попадают изображения из папки `raw/icons`.
58 changes: 58 additions & 0 deletions svgo.config.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
export default {
js2svg: {
indent: 2,
pretty: true,
},
multipass: true,
plugins: [
...[
"cleanupAttrs",
"cleanupEnableBackground",
"cleanupIds",
"cleanupListOfValues",
"cleanupNumericValues",
"collapseGroups",
"convertColors",
"convertEllipseToCircle",
"convertPathData",
"convertShapeToPath",
"convertStyleToAttrs",
"convertTransform",
"inlineStyles",
"mergePaths",
"mergeStyles",
"minifyStyles",
"moveElemsAttrsToGroup",
"moveGroupAttrsToElems",
"removeComments",
"removeDesc",
"removeDimensions",
"removeDoctype",
"removeEditorsNSData",
"removeEmptyAttrs",
"removeEmptyContainers",
"removeEmptyText",
"removeHiddenElems",
"removeMetadata",
"removeNonInheritableGroupAttrs",
"removeRasterImages",
"removeScriptElement",
"removeStyleElement",
"removeTitle",
"removeUnknownsAndDefaults",
"removeUnusedNS",
"removeUselessDefs",
"removeUselessStrokeAndFill",
"removeXMLProcInst",
"reusePaths",
"sortAttrs",
"sortDefsChildren",
].map((name) => ({
active: true,
name,
params: {
floatPrecision: 2,
},
})),
],
};
72 changes: 72 additions & 0 deletions tools/image.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
import { Image } from "imagescript";
import { readdir, readFile, rm, writeFile } from "node:fs/promises";
import path from "node:path";
import { optimize } from "svgo";

import svgoConfig from "../svgo.config.js";

export const imageSet = new Set([".jpg", ".png", ".svg"]);

export const processImage = async (filePath) => {
const filename = path.basename(filePath);
const extname = path.extname(filename);

if (extname === ".svg") {
const resultName = `${filePath.includes("icons") ? "src/icons" : "public/images"}/${filename}`;
await writeFile(
resultName,
optimize(await readFile(filePath, "utf-8"), svgoConfig).data.replaceAll(
"\\r\\n",
"\\n",
),
).then(() => console.info(`${resultName} created`));
} else {
const imageData = await readFile(filePath);
const image = await Image.decode(imageData);
const resultName = `public/images/${filename}`.replace(extname, ".webp");
const promises = [
writeFile(resultName, await image.encodeWEBP(80)).then(() =>
console.info(`${resultName} created`),
),
];

// Создаём уменьшенные копии, если в имени есть соотв. retina-индекс
const [, nameBasis, retinaNumber = "1"] = filename.match(/^(.*?)@(\d)x\./);
const retinaIndex = parseInt(retinaNumber, 10);
if (retinaIndex > 1) {
const { height, width } = image;
for (let i = retinaIndex - 1; i >= 1; i--) {
const coefficient = i / retinaIndex;
const resultRetinaName = `public/images/${nameBasis}@${i}x.webp`;
promises.push(
writeFile(
resultRetinaName,
await image
.clone()
.resize(width * coefficient, height * coefficient)
.encodeWEBP(80),
).then(() => console.info(`${resultRetinaName} created`)),
);
}
}

await Promise.all(promises);
}

await rm(filePath, { force: true });
};

export const processAllImages = async () => {
const filenames = await readdir("raw", { recursive: true });
const promises = [];
filenames.forEach((filename) => {
const extname = path.extname(filename);
if (
(filename.includes("icons") && extname === ".svg") ||
(filename.includes("images") && imageSet.has(extname))
) {
promises.push(processImage(`raw/${filename.replaceAll("\\", "/")}`));
}
});
await Promise.all(promises);
};
Loading

0 comments on commit b49c9ae

Please sign in to comment.