@semba-ryuichiro/webpify 1.1.0 → 1.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +16 -11
- package/dist/adapters/sharp-adapter/index.js +4 -1
- package/dist/cli/argument-parser/index.js +4 -0
- package/dist/cli/main/index.js +10 -5
- package/dist/core/converter/index.js +1 -0
- package/dist/ports/image-processor.d.ts +1 -0
- package/dist/types/index.d.ts +5 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -26,6 +26,7 @@ webpify は画像ファイル(PNG/JPEG/GIF)を WebP 形式に変換する CL
|
|
|
26
26
|
- 単一ファイルまたはディレクトリ一括変換
|
|
27
27
|
- 再帰的なディレクトリ走査
|
|
28
28
|
- 品質パラメータの指定(1-100)
|
|
29
|
+
- lossless(可逆圧縮)モード対応
|
|
29
30
|
- 出力先ディレクトリの指定
|
|
30
31
|
- 既存ファイルの上書き制御
|
|
31
32
|
- WebP ファイル一覧表示
|
|
@@ -53,17 +54,18 @@ webpify ./images -r
|
|
|
53
54
|
|
|
54
55
|
### オプション
|
|
55
56
|
|
|
56
|
-
| オプション | 説明
|
|
57
|
-
| -------------------- |
|
|
58
|
-
| `-o, --output <dir>` | 出力先ディレクトリ
|
|
59
|
-
| `-q, --quality <n>` | 品質(1-100)
|
|
60
|
-
| `-r, --recursive` | 再帰的に処理
|
|
61
|
-
| `-f, --force` | 既存ファイルを上書き
|
|
62
|
-
| `--
|
|
63
|
-
| `--
|
|
64
|
-
| `--
|
|
65
|
-
|
|
|
66
|
-
| `-
|
|
57
|
+
| オプション | 説明 | デフォルト |
|
|
58
|
+
| -------------------- | --------------- | ----- |
|
|
59
|
+
| `-o, --output <dir>` | 出力先ディレクトリ | 入力と同じ |
|
|
60
|
+
| `-q, --quality <n>` | 品質(1-100) | 100 |
|
|
61
|
+
| `-r, --recursive` | 再帰的に処理 | false |
|
|
62
|
+
| `-f, --force` | 既存ファイルを上書き | false |
|
|
63
|
+
| `--lossless` | 可逆圧縮モードで変換 | false |
|
|
64
|
+
| `--list` | WebP ファイル一覧表示 | - |
|
|
65
|
+
| `--absolute` | 一覧表示時に絶対パスで表示 | false |
|
|
66
|
+
| `--quiet` | 統計情報を非表示 | false |
|
|
67
|
+
| `-v, --version` | バージョン表示 | - |
|
|
68
|
+
| `-h, --help` | ヘルプ表示 | - |
|
|
67
69
|
|
|
68
70
|
### 例
|
|
69
71
|
|
|
@@ -74,6 +76,9 @@ webpify image.png -q 90
|
|
|
74
76
|
# 別ディレクトリに出力
|
|
75
77
|
webpify ./images -o ./webp-images
|
|
76
78
|
|
|
79
|
+
# lossless(可逆圧縮)モードで変換
|
|
80
|
+
webpify image.png --lossless
|
|
81
|
+
|
|
77
82
|
# 強制上書き + 再帰 + 静音
|
|
78
83
|
webpify ./images -r -f --quiet
|
|
79
84
|
```
|
|
@@ -6,7 +6,10 @@ import sharp from 'sharp';
|
|
|
6
6
|
export function createSharpAdapter() {
|
|
7
7
|
return {
|
|
8
8
|
async convertToWebP(inputPath, outputPath, options) {
|
|
9
|
-
|
|
9
|
+
// lossless モードの場合は lossless: true を設定(quality は無視される)
|
|
10
|
+
// lossy モードの場合は quality を設定
|
|
11
|
+
const webpOptions = options.lossless ? { lossless: true } : { quality: options.quality };
|
|
12
|
+
const result = await sharp(inputPath).webp(webpOptions).toFile(outputPath);
|
|
10
13
|
return { size: result.size };
|
|
11
14
|
},
|
|
12
15
|
async getMetadata(filePath) {
|
|
@@ -44,6 +44,7 @@ export function createArgumentParser() {
|
|
|
44
44
|
.option('-q, --quality <number>', '品質レベル (1-100)', parseQuality, DEFAULT_QUALITY)
|
|
45
45
|
.option('-r, --recursive', 'ディレクトリを再帰的に処理', false)
|
|
46
46
|
.option('-f, --force', '既存ファイルを上書き', false)
|
|
47
|
+
.option('--lossless', 'lossless(可逆圧縮)モードで変換', false)
|
|
47
48
|
.option('--quiet', 'サイレントモード(出力なし)', false)
|
|
48
49
|
.option('--list', 'WebP ファイルをサイズ情報付きで一覧表示', false)
|
|
49
50
|
.option('--absolute', '--list オプション使用時に絶対パスで表示', false)
|
|
@@ -62,6 +63,7 @@ export function createArgumentParser() {
|
|
|
62
63
|
force: false,
|
|
63
64
|
input: '',
|
|
64
65
|
list: false,
|
|
66
|
+
lossless: false,
|
|
65
67
|
quality: DEFAULT_QUALITY,
|
|
66
68
|
quiet: false,
|
|
67
69
|
recursive: false,
|
|
@@ -81,6 +83,7 @@ export function createArgumentParser() {
|
|
|
81
83
|
force: false,
|
|
82
84
|
input: '',
|
|
83
85
|
list: false,
|
|
86
|
+
lossless: false,
|
|
84
87
|
quality: DEFAULT_QUALITY,
|
|
85
88
|
quiet: false,
|
|
86
89
|
recursive: false,
|
|
@@ -96,6 +99,7 @@ export function createArgumentParser() {
|
|
|
96
99
|
force: options['force'],
|
|
97
100
|
input: args[0] || '',
|
|
98
101
|
list: options['list'],
|
|
102
|
+
lossless: options['lossless'],
|
|
99
103
|
output: options['output'],
|
|
100
104
|
quality: options['quality'],
|
|
101
105
|
quiet: options['quiet'],
|
package/dist/cli/main/index.js
CHANGED
|
@@ -37,9 +37,10 @@ export function createMain(deps) {
|
|
|
37
37
|
/**
|
|
38
38
|
* 単一ファイル変換モードを実行する
|
|
39
39
|
*/
|
|
40
|
-
async function executeSingleFileMode(inputPath, quality, force, output, quiet) {
|
|
40
|
+
async function executeSingleFileMode(inputPath, quality, force, output, quiet, lossless) {
|
|
41
41
|
const result = await converter.convert(inputPath, {
|
|
42
42
|
force,
|
|
43
|
+
lossless,
|
|
43
44
|
output,
|
|
44
45
|
quality,
|
|
45
46
|
});
|
|
@@ -49,7 +50,7 @@ export function createMain(deps) {
|
|
|
49
50
|
/**
|
|
50
51
|
* ディレクトリ変換モードを実行する
|
|
51
52
|
*/
|
|
52
|
-
async function executeDirectoryMode(inputPath, quality, force, output, recursive, quiet) {
|
|
53
|
+
async function executeDirectoryMode(inputPath, quality, force, output, recursive, quiet, lossless) {
|
|
53
54
|
const files = await fileScanner.scan(inputPath, {
|
|
54
55
|
extensions: CONVERT_EXTENSIONS,
|
|
55
56
|
recursive,
|
|
@@ -66,7 +67,7 @@ export function createMain(deps) {
|
|
|
66
67
|
reporter.reportConversion(result, quiet);
|
|
67
68
|
}
|
|
68
69
|
};
|
|
69
|
-
const stats = await converter.convertBatch(files, { force, output, quality }, onProgress);
|
|
70
|
+
const stats = await converter.convertBatch(files, { force, lossless, output, quality }, onProgress);
|
|
70
71
|
if (!quiet) {
|
|
71
72
|
reporter.reportStats(stats);
|
|
72
73
|
}
|
|
@@ -86,6 +87,10 @@ export function createMain(deps) {
|
|
|
86
87
|
process.stderr.write(`Error: File not found: ${options.input}\n`);
|
|
87
88
|
return 1;
|
|
88
89
|
}
|
|
90
|
+
// lossless と quality の同時指定時に警告を出す(quality がデフォルト値でない場合)
|
|
91
|
+
if (options.lossless && options.quality !== 100 && !options.quiet) {
|
|
92
|
+
process.stderr.write('警告: --lossless と --quality が同時に指定されています。lossless モードでは quality は無視されます。\n');
|
|
93
|
+
}
|
|
89
94
|
// 一覧表示モード(--list オプション)
|
|
90
95
|
if (options.list) {
|
|
91
96
|
const isDir = await fileScanner.isDirectory(options.input);
|
|
@@ -109,10 +114,10 @@ export function createMain(deps) {
|
|
|
109
114
|
const isDirectory = await fileScanner.isDirectory(options.input);
|
|
110
115
|
if (isDirectory) {
|
|
111
116
|
// ディレクトリ変換モード
|
|
112
|
-
return executeDirectoryMode(options.input, options.quality, options.force, options.output, options.recursive, options.quiet);
|
|
117
|
+
return executeDirectoryMode(options.input, options.quality, options.force, options.output, options.recursive, options.quiet, options.lossless);
|
|
113
118
|
}
|
|
114
119
|
// 単一ファイル変換モード
|
|
115
|
-
return executeSingleFileMode(options.input, options.quality, options.force, options.output, options.quiet);
|
|
120
|
+
return executeSingleFileMode(options.input, options.quality, options.force, options.output, options.quiet, options.lossless);
|
|
116
121
|
},
|
|
117
122
|
};
|
|
118
123
|
}
|
package/dist/types/index.d.ts
CHANGED
|
@@ -8,10 +8,12 @@ export type SupportedFormat = 'png' | 'jpeg' | 'jpg' | 'gif';
|
|
|
8
8
|
export interface ConvertOptions {
|
|
9
9
|
/** 出力先パス(省略時は入力ファイルと同じディレクトリ) */
|
|
10
10
|
output?: string | undefined;
|
|
11
|
-
/** 変換品質(1-100、デフォルト:
|
|
11
|
+
/** 変換品質(1-100、デフォルト: 100) */
|
|
12
12
|
quality: number;
|
|
13
13
|
/** 既存ファイルを上書きするかどうか */
|
|
14
14
|
force: boolean;
|
|
15
|
+
/** lossless(可逆圧縮)モードで変換するかどうか */
|
|
16
|
+
lossless: boolean;
|
|
15
17
|
}
|
|
16
18
|
/**
|
|
17
19
|
* 単一ファイルの変換結果
|
|
@@ -91,6 +93,8 @@ export interface ParsedOptions {
|
|
|
91
93
|
list: boolean;
|
|
92
94
|
/** 一覧表示時に絶対パスで表示するか */
|
|
93
95
|
absolutePath: boolean;
|
|
96
|
+
/** lossless(可逆圧縮)モードで変換するか */
|
|
97
|
+
lossless: boolean;
|
|
94
98
|
}
|
|
95
99
|
/**
|
|
96
100
|
* 一覧表示用の画像アイテム
|