peasy-image 0.1.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/LICENSE +21 -0
- package/README.md +287 -0
- package/dist/index.d.ts +188 -0
- package/dist/index.js +121 -0
- package/package.json +46 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Peasy Tools
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,287 @@
|
|
|
1
|
+
# peasy-image
|
|
2
|
+
|
|
3
|
+
[](https://www.npmjs.com/package/peasy-image)
|
|
4
|
+
[](https://www.typescriptlang.org/)
|
|
5
|
+
[](https://opensource.org/licenses/MIT)
|
|
6
|
+
|
|
7
|
+
Image processing library for Node.js powered by [sharp](https://sharp.pixelplumbing.com/) -- resize, crop, convert, compress, rotate, blur, sharpen, and 8 more operations. TypeScript-first with full type definitions.
|
|
8
|
+
|
|
9
|
+
All functions accept a `Buffer` and return a `Promise<ImageResult>` with the processed image data, dimensions, format, and byte size.
|
|
10
|
+
|
|
11
|
+
> **Try the interactive tools at [peasyimage.com](https://peasyimage.com)** -- [Image Resizer](https://peasyimage.com/tools/resize/), [Image Converter](https://peasyimage.com/tools/convert/), [Image Compressor](https://peasyimage.com/tools/compress/)
|
|
12
|
+
|
|
13
|
+
## Table of Contents
|
|
14
|
+
|
|
15
|
+
- [Install](#install)
|
|
16
|
+
- [Quick Start](#quick-start)
|
|
17
|
+
- [What You Can Do](#what-you-can-do)
|
|
18
|
+
- [Resize and Crop](#resize-and-crop)
|
|
19
|
+
- [Format Conversion](#format-conversion)
|
|
20
|
+
- [Compression](#compression)
|
|
21
|
+
- [Rotation and Flipping](#rotation-and-flipping)
|
|
22
|
+
- [Filters and Effects](#filters-and-effects)
|
|
23
|
+
- [Compositing](#compositing)
|
|
24
|
+
- [Thumbnails](#thumbnails)
|
|
25
|
+
- [API Reference](#api-reference)
|
|
26
|
+
- [TypeScript Types](#typescript-types)
|
|
27
|
+
- [Also Available for Python](#also-available-for-python)
|
|
28
|
+
- [Peasy Developer Tools](#peasy-developer-tools)
|
|
29
|
+
- [License](#license)
|
|
30
|
+
|
|
31
|
+
## Install
|
|
32
|
+
|
|
33
|
+
```bash
|
|
34
|
+
npm install peasy-image
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
Requires Node.js 18+ and includes [sharp](https://sharp.pixelplumbing.com/) as a dependency for high-performance, native image processing.
|
|
38
|
+
|
|
39
|
+
## Quick Start
|
|
40
|
+
|
|
41
|
+
```typescript
|
|
42
|
+
import { readFileSync, writeFileSync } from "fs";
|
|
43
|
+
import { info, resize, compress, convert } from "peasy-image";
|
|
44
|
+
|
|
45
|
+
const source = readFileSync("photo.jpg");
|
|
46
|
+
|
|
47
|
+
// Get image metadata
|
|
48
|
+
const meta = await info(source);
|
|
49
|
+
console.log(`${meta.width}x${meta.height} ${meta.format} (${meta.size} bytes)`);
|
|
50
|
+
|
|
51
|
+
// Resize to 800px wide, maintaining aspect ratio
|
|
52
|
+
const resized = await resize(source, { width: 800, fit: "contain" });
|
|
53
|
+
writeFileSync("resized.jpg", resized.data);
|
|
54
|
+
|
|
55
|
+
// Compress to WebP at quality 60
|
|
56
|
+
const compressed = await compress(source, { quality: 60, format: "webp" });
|
|
57
|
+
writeFileSync("compressed.webp", compressed.data);
|
|
58
|
+
|
|
59
|
+
// Convert PNG to AVIF
|
|
60
|
+
const avif = await convert(readFileSync("image.png"), "avif");
|
|
61
|
+
writeFileSync("image.avif", avif.data);
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
## What You Can Do
|
|
65
|
+
|
|
66
|
+
### Resize and Crop
|
|
67
|
+
|
|
68
|
+
Resize images to exact dimensions or proportionally by width/height. Sharp supports 5 fit modes that control how the image fills the target area: `cover` (crop to fill), `contain` (letterbox), `fill` (stretch), `inside`, and `outside`.
|
|
69
|
+
|
|
70
|
+
| Fit Mode | Behavior |
|
|
71
|
+
|----------|----------|
|
|
72
|
+
| `cover` | Crop to fill the target dimensions (default) |
|
|
73
|
+
| `contain` | Resize to fit within bounds, preserving aspect ratio |
|
|
74
|
+
| `fill` | Stretch to exact dimensions, ignoring aspect ratio |
|
|
75
|
+
| `inside` | Resize to fit inside, never enlarging |
|
|
76
|
+
| `outside` | Resize to cover, never shrinking |
|
|
77
|
+
|
|
78
|
+
```typescript
|
|
79
|
+
import { resize, crop } from "peasy-image";
|
|
80
|
+
|
|
81
|
+
// Resize to fit within 800x600, preserving aspect ratio
|
|
82
|
+
const fitted = await resize(source, { width: 800, height: 600, fit: "contain" });
|
|
83
|
+
|
|
84
|
+
// Resize by width only — height calculated automatically
|
|
85
|
+
const wide = await resize(source, { width: 1200, fit: "contain" });
|
|
86
|
+
|
|
87
|
+
// Crop a 300x300 region starting at (50, 100)
|
|
88
|
+
const cropped = await crop(source, { left: 50, top: 100, width: 300, height: 300 });
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
Learn more: [Image Resizer Tool](https://peasyimage.com/tools/resize/) -- [Image Cropper Tool](https://peasyimage.com/tools/crop/)
|
|
92
|
+
|
|
93
|
+
### Format Conversion
|
|
94
|
+
|
|
95
|
+
Convert between 6 image formats. Modern formats like WebP and AVIF provide significantly better compression than JPEG and PNG while maintaining visual quality.
|
|
96
|
+
|
|
97
|
+
| Format | Best For | Alpha Support |
|
|
98
|
+
|--------|----------|---------------|
|
|
99
|
+
| `png` | Lossless graphics, screenshots | Yes |
|
|
100
|
+
| `jpeg` | Photos, continuous tones | No |
|
|
101
|
+
| `webp` | Web images (25-35% smaller than JPEG) | Yes |
|
|
102
|
+
| `avif` | Next-gen web (50% smaller than JPEG) | Yes |
|
|
103
|
+
| `tiff` | Print, archival | Yes |
|
|
104
|
+
| `gif` | Simple animations | Limited |
|
|
105
|
+
|
|
106
|
+
```typescript
|
|
107
|
+
import { convert } from "peasy-image";
|
|
108
|
+
|
|
109
|
+
// Convert to WebP for smaller web assets
|
|
110
|
+
const webp = await convert(source, "webp");
|
|
111
|
+
|
|
112
|
+
// Convert to AVIF for maximum compression
|
|
113
|
+
const avif = await convert(source, "avif");
|
|
114
|
+
```
|
|
115
|
+
|
|
116
|
+
Learn more: [Image Converter Tool](https://peasyimage.com/tools/convert/) -- [WebP vs AVIF Guide](https://peasyimage.com/blog/webp-vs-avif/)
|
|
117
|
+
|
|
118
|
+
### Compression
|
|
119
|
+
|
|
120
|
+
Reduce file size by adjusting quality. The `compress` function defaults to JPEG at quality 60, which typically reduces file size by 70-80% with acceptable visual quality.
|
|
121
|
+
|
|
122
|
+
```typescript
|
|
123
|
+
import { compress } from "peasy-image";
|
|
124
|
+
|
|
125
|
+
// Compress to JPEG at quality 60 (default)
|
|
126
|
+
const small = await compress(source);
|
|
127
|
+
|
|
128
|
+
// Compress to WebP at quality 80 for higher fidelity
|
|
129
|
+
const webp = await compress(source, { quality: 80, format: "webp" });
|
|
130
|
+
```
|
|
131
|
+
|
|
132
|
+
Learn more: [Image Compressor Tool](https://peasyimage.com/tools/compress/)
|
|
133
|
+
|
|
134
|
+
### Rotation and Flipping
|
|
135
|
+
|
|
136
|
+
Rotate images by any angle (90, 180, 270 for lossless, or arbitrary degrees). Flip vertically or mirror horizontally.
|
|
137
|
+
|
|
138
|
+
```typescript
|
|
139
|
+
import { rotate, flip, flop } from "peasy-image";
|
|
140
|
+
|
|
141
|
+
// Rotate 90 degrees clockwise
|
|
142
|
+
const rotated = await rotate(source, 90);
|
|
143
|
+
|
|
144
|
+
// Flip vertically (top to bottom)
|
|
145
|
+
const flipped = await flip(source);
|
|
146
|
+
|
|
147
|
+
// Mirror horizontally (left to right)
|
|
148
|
+
const mirrored = await flop(source);
|
|
149
|
+
```
|
|
150
|
+
|
|
151
|
+
### Filters and Effects
|
|
152
|
+
|
|
153
|
+
Apply visual effects: grayscale conversion, Gaussian blur, Laplacian sharpening, color inversion, and color tinting.
|
|
154
|
+
|
|
155
|
+
| Filter | Description | Key Parameter |
|
|
156
|
+
|--------|-------------|---------------|
|
|
157
|
+
| `grayscale` | Convert to grayscale | -- |
|
|
158
|
+
| `blur` | Gaussian blur | `sigma` (0.3-1000, default 2.0) |
|
|
159
|
+
| `sharpen` | Laplacian sharpening | `sigma` (default 1.0) |
|
|
160
|
+
| `negate` | Invert all colors | -- |
|
|
161
|
+
| `tint` | Apply RGB color tint | `{ r, g, b }` values |
|
|
162
|
+
|
|
163
|
+
```typescript
|
|
164
|
+
import { grayscale, blur, sharpen, negate, tint } from "peasy-image";
|
|
165
|
+
|
|
166
|
+
// Convert to black and white
|
|
167
|
+
const bw = await grayscale(source);
|
|
168
|
+
|
|
169
|
+
// Apply soft Gaussian blur (sigma 3.0)
|
|
170
|
+
const blurred = await blur(source, 3.0);
|
|
171
|
+
|
|
172
|
+
// Sharpen a slightly out-of-focus image
|
|
173
|
+
const sharp = await sharpen(source, 1.5);
|
|
174
|
+
|
|
175
|
+
// Invert colors for a negative effect
|
|
176
|
+
const inverted = await negate(source);
|
|
177
|
+
|
|
178
|
+
// Apply a warm sepia-like tint
|
|
179
|
+
const warm = await tint(source, { r: 180, g: 130, b: 80 });
|
|
180
|
+
```
|
|
181
|
+
|
|
182
|
+
### Compositing
|
|
183
|
+
|
|
184
|
+
Overlay one image on top of another with position control and opacity. Useful for watermarks, badges, and image collages.
|
|
185
|
+
|
|
186
|
+
```typescript
|
|
187
|
+
import { composite } from "peasy-image";
|
|
188
|
+
|
|
189
|
+
// Place a watermark at position (10, 10)
|
|
190
|
+
const watermarked = await composite(photo, watermarkPng, { left: 10, top: 10 });
|
|
191
|
+
|
|
192
|
+
// Overlay with 50% opacity
|
|
193
|
+
const blended = await composite(background, foreground, {
|
|
194
|
+
left: 100,
|
|
195
|
+
top: 50,
|
|
196
|
+
opacity: 0.5,
|
|
197
|
+
});
|
|
198
|
+
```
|
|
199
|
+
|
|
200
|
+
### Thumbnails
|
|
201
|
+
|
|
202
|
+
Create square thumbnails by center-cropping and resizing in a single operation. Ideal for profile pictures, gallery previews, and social media icons.
|
|
203
|
+
|
|
204
|
+
```typescript
|
|
205
|
+
import { thumbnail } from "peasy-image";
|
|
206
|
+
|
|
207
|
+
// 64x64 square thumbnail for avatars
|
|
208
|
+
const avatar = await thumbnail(source, 64);
|
|
209
|
+
|
|
210
|
+
// 256x256 thumbnail for gallery grid
|
|
211
|
+
const preview = await thumbnail(source, 256);
|
|
212
|
+
```
|
|
213
|
+
|
|
214
|
+
## API Reference
|
|
215
|
+
|
|
216
|
+
| Function | Signature | Description |
|
|
217
|
+
|----------|-----------|-------------|
|
|
218
|
+
| `info` | `(source: Buffer) => Promise<ImageInfo>` | Get image metadata (dimensions, format, channels) |
|
|
219
|
+
| `resize` | `(source: Buffer, options: ResizeOptions) => Promise<ImageResult>` | Resize with fit mode control |
|
|
220
|
+
| `crop` | `(source: Buffer, options: CropOptions) => Promise<ImageResult>` | Extract a rectangular region |
|
|
221
|
+
| `convert` | `(source: Buffer, format: ImageFormat) => Promise<ImageResult>` | Convert between 6 formats |
|
|
222
|
+
| `compress` | `(source: Buffer, options?: CompressOptions) => Promise<ImageResult>` | Reduce file size via quality |
|
|
223
|
+
| `rotate` | `(source: Buffer, angle: number) => Promise<ImageResult>` | Rotate by degrees |
|
|
224
|
+
| `flip` | `(source: Buffer) => Promise<ImageResult>` | Flip vertically |
|
|
225
|
+
| `flop` | `(source: Buffer) => Promise<ImageResult>` | Mirror horizontally |
|
|
226
|
+
| `grayscale` | `(source: Buffer) => Promise<ImageResult>` | Convert to grayscale |
|
|
227
|
+
| `blur` | `(source: Buffer, sigma?: number) => Promise<ImageResult>` | Gaussian blur |
|
|
228
|
+
| `sharpen` | `(source: Buffer, sigma?: number) => Promise<ImageResult>` | Laplacian sharpening |
|
|
229
|
+
| `negate` | `(source: Buffer) => Promise<ImageResult>` | Invert colors |
|
|
230
|
+
| `tint` | `(source: Buffer, color: {r,g,b}) => Promise<ImageResult>` | Apply color tint |
|
|
231
|
+
| `composite` | `(base: Buffer, overlay: Buffer, options?) => Promise<ImageResult>` | Overlay images |
|
|
232
|
+
| `thumbnail` | `(source: Buffer, size: number) => Promise<ImageResult>` | Square center-crop thumbnail |
|
|
233
|
+
|
|
234
|
+
## TypeScript Types
|
|
235
|
+
|
|
236
|
+
```typescript
|
|
237
|
+
interface ImageInfo {
|
|
238
|
+
width: number;
|
|
239
|
+
height: number;
|
|
240
|
+
format: string;
|
|
241
|
+
channels: number;
|
|
242
|
+
size: number;
|
|
243
|
+
hasAlpha: boolean;
|
|
244
|
+
space: string;
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
interface ImageResult {
|
|
248
|
+
data: Buffer;
|
|
249
|
+
width: number;
|
|
250
|
+
height: number;
|
|
251
|
+
format: string;
|
|
252
|
+
size: number;
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
type ImageFormat = "png" | "jpeg" | "webp" | "avif" | "tiff" | "gif";
|
|
256
|
+
type FitMode = "cover" | "contain" | "fill" | "inside" | "outside";
|
|
257
|
+
|
|
258
|
+
interface ResizeOptions { width?: number; height?: number; fit?: FitMode; }
|
|
259
|
+
interface CropOptions { left: number; top: number; width: number; height: number; }
|
|
260
|
+
interface CompressOptions { quality?: number; format?: ImageFormat; }
|
|
261
|
+
```
|
|
262
|
+
|
|
263
|
+
## Also Available for Python
|
|
264
|
+
|
|
265
|
+
| Platform | Package | Install |
|
|
266
|
+
|----------|---------|---------|
|
|
267
|
+
| **PyPI** | [peasy-image](https://pypi.org/project/peasy-image/) | `pip install peasy-image` |
|
|
268
|
+
|
|
269
|
+
The Python version provides 20 operations powered by Pillow, including watermark, border, round corners, pad, and EXIF extraction.
|
|
270
|
+
|
|
271
|
+
## Peasy Developer Tools
|
|
272
|
+
|
|
273
|
+
| Package | npm | PyPI | Description |
|
|
274
|
+
|---------|-----|------|-------------|
|
|
275
|
+
| **peasy-image** | **[npm](https://www.npmjs.com/package/peasy-image)** | [PyPI](https://pypi.org/project/peasy-image/) | **Image processing — resize, crop, convert, compress** |
|
|
276
|
+
| peasy-pdf | [npm](https://www.npmjs.com/package/peasy-pdf) | [PyPI](https://pypi.org/project/peasy-pdf/) | PDF manipulation -- merge, split, rotate, extract |
|
|
277
|
+
| peasy-css | [npm](https://www.npmjs.com/package/peasy-css) | [PyPI](https://pypi.org/project/peasy-css/) | CSS processing -- minify, format, analyze |
|
|
278
|
+
| peasy-compress | -- | [PyPI](https://pypi.org/project/peasy-compress/) | File compression -- gzip, brotli, zstd |
|
|
279
|
+
| peasy-audio | -- | [PyPI](https://pypi.org/project/peasy-audio/) | Audio processing -- convert, trim, metadata |
|
|
280
|
+
| peasy-video | -- | [PyPI](https://pypi.org/project/peasy-video/) | Video processing -- convert, trim, thumbnail |
|
|
281
|
+
| peasy-document | [npm](https://www.npmjs.com/package/peasy-document) | [PyPI](https://pypi.org/project/peasy-document/) | Document conversion -- DOCX, HTML, Markdown |
|
|
282
|
+
|
|
283
|
+
Part of the [Peasy Tools](https://peasytools.com) developer tools ecosystem.
|
|
284
|
+
|
|
285
|
+
## License
|
|
286
|
+
|
|
287
|
+
MIT
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,188 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* peasy-image types — interfaces for image processing operations.
|
|
3
|
+
*/
|
|
4
|
+
/** Basic image metadata returned by `info()`. */
|
|
5
|
+
interface ImageInfo {
|
|
6
|
+
width: number;
|
|
7
|
+
height: number;
|
|
8
|
+
format: string;
|
|
9
|
+
channels: number;
|
|
10
|
+
size: number;
|
|
11
|
+
hasAlpha: boolean;
|
|
12
|
+
space: string;
|
|
13
|
+
}
|
|
14
|
+
/** Result of an image processing operation. */
|
|
15
|
+
interface ImageResult {
|
|
16
|
+
data: Buffer;
|
|
17
|
+
width: number;
|
|
18
|
+
height: number;
|
|
19
|
+
format: string;
|
|
20
|
+
size: number;
|
|
21
|
+
}
|
|
22
|
+
/** Supported output image formats. */
|
|
23
|
+
type ImageFormat = "png" | "jpeg" | "webp" | "avif" | "tiff" | "gif";
|
|
24
|
+
/** Resize fit mode — how the image should fit within the target dimensions. */
|
|
25
|
+
type FitMode = "cover" | "contain" | "fill" | "inside" | "outside";
|
|
26
|
+
/** Options for resizing an image. */
|
|
27
|
+
interface ResizeOptions {
|
|
28
|
+
width?: number;
|
|
29
|
+
height?: number;
|
|
30
|
+
fit?: FitMode;
|
|
31
|
+
}
|
|
32
|
+
/** Options for cropping a region from an image. */
|
|
33
|
+
interface CropOptions {
|
|
34
|
+
left: number;
|
|
35
|
+
top: number;
|
|
36
|
+
width: number;
|
|
37
|
+
height: number;
|
|
38
|
+
}
|
|
39
|
+
/** Options for compressing an image. */
|
|
40
|
+
interface CompressOptions {
|
|
41
|
+
quality?: number;
|
|
42
|
+
format?: ImageFormat;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
/**
|
|
46
|
+
* peasy-image engine — image processing functions powered by sharp.
|
|
47
|
+
*
|
|
48
|
+
* 15 operations: info, resize, crop, convert, compress, rotate, flip, flop,
|
|
49
|
+
* grayscale, blur, sharpen, negate, tint, composite, thumbnail.
|
|
50
|
+
*/
|
|
51
|
+
|
|
52
|
+
/**
|
|
53
|
+
* Get image metadata — dimensions, format, channels, color space.
|
|
54
|
+
*
|
|
55
|
+
* @param source - Image data as a Buffer
|
|
56
|
+
* @returns Image metadata
|
|
57
|
+
*/
|
|
58
|
+
declare function info(source: Buffer): Promise<ImageInfo>;
|
|
59
|
+
/**
|
|
60
|
+
* Resize an image to the given dimensions.
|
|
61
|
+
*
|
|
62
|
+
* If only width or height is provided, the other dimension is
|
|
63
|
+
* calculated to maintain aspect ratio (default fit: "cover").
|
|
64
|
+
*
|
|
65
|
+
* @param source - Image data as a Buffer
|
|
66
|
+
* @param options - Resize options (width, height, fit)
|
|
67
|
+
* @returns Resized image result
|
|
68
|
+
*/
|
|
69
|
+
declare function resize(source: Buffer, options: ResizeOptions): Promise<ImageResult>;
|
|
70
|
+
/**
|
|
71
|
+
* Crop a rectangular region from an image.
|
|
72
|
+
*
|
|
73
|
+
* @param source - Image data as a Buffer
|
|
74
|
+
* @param options - Crop region (left, top, width, height)
|
|
75
|
+
* @returns Cropped image result
|
|
76
|
+
*/
|
|
77
|
+
declare function crop(source: Buffer, options: CropOptions): Promise<ImageResult>;
|
|
78
|
+
/**
|
|
79
|
+
* Convert an image to a different format.
|
|
80
|
+
*
|
|
81
|
+
* @param source - Image data as a Buffer
|
|
82
|
+
* @param format - Target format (png, jpeg, webp, avif, tiff, gif)
|
|
83
|
+
* @returns Converted image result
|
|
84
|
+
*/
|
|
85
|
+
declare function convert(source: Buffer, format: ImageFormat): Promise<ImageResult>;
|
|
86
|
+
/**
|
|
87
|
+
* Compress an image by reducing quality.
|
|
88
|
+
*
|
|
89
|
+
* Defaults to JPEG format at quality 60 for maximum compression.
|
|
90
|
+
*
|
|
91
|
+
* @param source - Image data as a Buffer
|
|
92
|
+
* @param options - Compression options (quality, format)
|
|
93
|
+
* @returns Compressed image result
|
|
94
|
+
*/
|
|
95
|
+
declare function compress(source: Buffer, options?: CompressOptions): Promise<ImageResult>;
|
|
96
|
+
/**
|
|
97
|
+
* Rotate an image by the given angle in degrees.
|
|
98
|
+
*
|
|
99
|
+
* Common angles (90, 180, 270) produce lossless rotation.
|
|
100
|
+
* Arbitrary angles expand the canvas to fit the rotated image.
|
|
101
|
+
*
|
|
102
|
+
* @param source - Image data as a Buffer
|
|
103
|
+
* @param angle - Rotation angle in degrees (clockwise)
|
|
104
|
+
* @returns Rotated image result
|
|
105
|
+
*/
|
|
106
|
+
declare function rotate(source: Buffer, angle: number): Promise<ImageResult>;
|
|
107
|
+
/**
|
|
108
|
+
* Flip an image vertically (top to bottom).
|
|
109
|
+
*
|
|
110
|
+
* @param source - Image data as a Buffer
|
|
111
|
+
* @returns Flipped image result
|
|
112
|
+
*/
|
|
113
|
+
declare function flip(source: Buffer): Promise<ImageResult>;
|
|
114
|
+
/**
|
|
115
|
+
* Flop an image horizontally (mirror, left to right).
|
|
116
|
+
*
|
|
117
|
+
* @param source - Image data as a Buffer
|
|
118
|
+
* @returns Flopped image result
|
|
119
|
+
*/
|
|
120
|
+
declare function flop(source: Buffer): Promise<ImageResult>;
|
|
121
|
+
/**
|
|
122
|
+
* Convert an image to grayscale.
|
|
123
|
+
*
|
|
124
|
+
* @param source - Image data as a Buffer
|
|
125
|
+
* @returns Grayscale image result
|
|
126
|
+
*/
|
|
127
|
+
declare function grayscale(source: Buffer): Promise<ImageResult>;
|
|
128
|
+
/**
|
|
129
|
+
* Apply Gaussian blur to an image.
|
|
130
|
+
*
|
|
131
|
+
* @param source - Image data as a Buffer
|
|
132
|
+
* @param sigma - Blur intensity (0.3 to 1000, default 2.0)
|
|
133
|
+
* @returns Blurred image result
|
|
134
|
+
*/
|
|
135
|
+
declare function blur(source: Buffer, sigma?: number): Promise<ImageResult>;
|
|
136
|
+
/**
|
|
137
|
+
* Sharpen an image using Laplacian sharpening.
|
|
138
|
+
*
|
|
139
|
+
* @param source - Image data as a Buffer
|
|
140
|
+
* @param sigma - Sharpening intensity (default 1.0)
|
|
141
|
+
* @returns Sharpened image result
|
|
142
|
+
*/
|
|
143
|
+
declare function sharpen(source: Buffer, sigma?: number): Promise<ImageResult>;
|
|
144
|
+
/**
|
|
145
|
+
* Negate (invert) the colors of an image.
|
|
146
|
+
*
|
|
147
|
+
* @param source - Image data as a Buffer
|
|
148
|
+
* @returns Negated image result
|
|
149
|
+
*/
|
|
150
|
+
declare function negate(source: Buffer): Promise<ImageResult>;
|
|
151
|
+
/**
|
|
152
|
+
* Apply a color tint to an image.
|
|
153
|
+
*
|
|
154
|
+
* @param source - Image data as a Buffer
|
|
155
|
+
* @param color - RGB color to tint with
|
|
156
|
+
* @returns Tinted image result
|
|
157
|
+
*/
|
|
158
|
+
declare function tint(source: Buffer, color: {
|
|
159
|
+
r: number;
|
|
160
|
+
g: number;
|
|
161
|
+
b: number;
|
|
162
|
+
}): Promise<ImageResult>;
|
|
163
|
+
/**
|
|
164
|
+
* Overlay one image on top of another (composite).
|
|
165
|
+
*
|
|
166
|
+
* @param base - Base image data as a Buffer
|
|
167
|
+
* @param overlay - Overlay image data as a Buffer
|
|
168
|
+
* @param options - Position and opacity options
|
|
169
|
+
* @returns Composited image result
|
|
170
|
+
*/
|
|
171
|
+
declare function composite(base: Buffer, overlay: Buffer, options?: {
|
|
172
|
+
left?: number;
|
|
173
|
+
top?: number;
|
|
174
|
+
opacity?: number;
|
|
175
|
+
}): Promise<ImageResult>;
|
|
176
|
+
/**
|
|
177
|
+
* Create a square thumbnail by center-cropping and resizing.
|
|
178
|
+
*
|
|
179
|
+
* The image is resized to cover the target size, then center-cropped
|
|
180
|
+
* to produce a square output.
|
|
181
|
+
*
|
|
182
|
+
* @param source - Image data as a Buffer
|
|
183
|
+
* @param size - Target thumbnail size in pixels (width = height)
|
|
184
|
+
* @returns Square thumbnail image result
|
|
185
|
+
*/
|
|
186
|
+
declare function thumbnail(source: Buffer, size: number): Promise<ImageResult>;
|
|
187
|
+
|
|
188
|
+
export { type CompressOptions, type CropOptions, type FitMode, type ImageFormat, type ImageInfo, type ImageResult, type ResizeOptions, blur, composite, compress, convert, crop, flip, flop, grayscale, info, negate, resize, rotate, sharpen, thumbnail, tint };
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,121 @@
|
|
|
1
|
+
// src/engine.ts
|
|
2
|
+
import sharp from "sharp";
|
|
3
|
+
async function toResult(pipeline, format) {
|
|
4
|
+
const { data, info: info2 } = await pipeline.toBuffer({ resolveWithObject: true });
|
|
5
|
+
return {
|
|
6
|
+
data,
|
|
7
|
+
width: info2.width,
|
|
8
|
+
height: info2.height,
|
|
9
|
+
format: info2.format || format || "unknown",
|
|
10
|
+
size: data.length
|
|
11
|
+
};
|
|
12
|
+
}
|
|
13
|
+
async function info(source) {
|
|
14
|
+
const meta = await sharp(source).metadata();
|
|
15
|
+
return {
|
|
16
|
+
width: meta.width ?? 0,
|
|
17
|
+
height: meta.height ?? 0,
|
|
18
|
+
format: meta.format ?? "unknown",
|
|
19
|
+
channels: meta.channels ?? 0,
|
|
20
|
+
size: source.length,
|
|
21
|
+
hasAlpha: meta.hasAlpha ?? false,
|
|
22
|
+
space: meta.space ?? "unknown"
|
|
23
|
+
};
|
|
24
|
+
}
|
|
25
|
+
async function resize(source, options) {
|
|
26
|
+
const pipeline = sharp(source).resize({
|
|
27
|
+
width: options.width,
|
|
28
|
+
height: options.height,
|
|
29
|
+
fit: options.fit ?? "cover"
|
|
30
|
+
});
|
|
31
|
+
return toResult(pipeline);
|
|
32
|
+
}
|
|
33
|
+
async function crop(source, options) {
|
|
34
|
+
const pipeline = sharp(source).extract({
|
|
35
|
+
left: options.left,
|
|
36
|
+
top: options.top,
|
|
37
|
+
width: options.width,
|
|
38
|
+
height: options.height
|
|
39
|
+
});
|
|
40
|
+
return toResult(pipeline);
|
|
41
|
+
}
|
|
42
|
+
async function convert(source, format) {
|
|
43
|
+
const pipeline = sharp(source).toFormat(format);
|
|
44
|
+
return toResult(pipeline, format);
|
|
45
|
+
}
|
|
46
|
+
async function compress(source, options) {
|
|
47
|
+
const quality = options?.quality ?? 60;
|
|
48
|
+
const format = options?.format ?? "jpeg";
|
|
49
|
+
const pipeline = sharp(source).toFormat(format, { quality });
|
|
50
|
+
return toResult(pipeline, format);
|
|
51
|
+
}
|
|
52
|
+
async function rotate(source, angle) {
|
|
53
|
+
const pipeline = sharp(source).rotate(angle);
|
|
54
|
+
return toResult(pipeline);
|
|
55
|
+
}
|
|
56
|
+
async function flip(source) {
|
|
57
|
+
const pipeline = sharp(source).flip();
|
|
58
|
+
return toResult(pipeline);
|
|
59
|
+
}
|
|
60
|
+
async function flop(source) {
|
|
61
|
+
const pipeline = sharp(source).flop();
|
|
62
|
+
return toResult(pipeline);
|
|
63
|
+
}
|
|
64
|
+
async function grayscale(source) {
|
|
65
|
+
const pipeline = sharp(source).grayscale();
|
|
66
|
+
return toResult(pipeline);
|
|
67
|
+
}
|
|
68
|
+
async function blur(source, sigma = 2) {
|
|
69
|
+
const pipeline = sharp(source).blur(sigma);
|
|
70
|
+
return toResult(pipeline);
|
|
71
|
+
}
|
|
72
|
+
async function sharpen(source, sigma = 1) {
|
|
73
|
+
const pipeline = sharp(source).sharpen(sigma);
|
|
74
|
+
return toResult(pipeline);
|
|
75
|
+
}
|
|
76
|
+
async function negate(source) {
|
|
77
|
+
const pipeline = sharp(source).negate();
|
|
78
|
+
return toResult(pipeline);
|
|
79
|
+
}
|
|
80
|
+
async function tint(source, color) {
|
|
81
|
+
const pipeline = sharp(source).tint(color);
|
|
82
|
+
return toResult(pipeline);
|
|
83
|
+
}
|
|
84
|
+
async function composite(base, overlay, options) {
|
|
85
|
+
let overlayInput = overlay;
|
|
86
|
+
if (options?.opacity !== void 0 && options.opacity < 1) {
|
|
87
|
+
overlayInput = await sharp(overlay).ensureAlpha(options.opacity).toBuffer();
|
|
88
|
+
}
|
|
89
|
+
const pipeline = sharp(base).composite([
|
|
90
|
+
{
|
|
91
|
+
input: overlayInput,
|
|
92
|
+
left: options?.left ?? 0,
|
|
93
|
+
top: options?.top ?? 0
|
|
94
|
+
}
|
|
95
|
+
]);
|
|
96
|
+
return toResult(pipeline);
|
|
97
|
+
}
|
|
98
|
+
async function thumbnail(source, size) {
|
|
99
|
+
const pipeline = sharp(source).resize(size, size, {
|
|
100
|
+
fit: "cover",
|
|
101
|
+
position: "centre"
|
|
102
|
+
});
|
|
103
|
+
return toResult(pipeline);
|
|
104
|
+
}
|
|
105
|
+
export {
|
|
106
|
+
blur,
|
|
107
|
+
composite,
|
|
108
|
+
compress,
|
|
109
|
+
convert,
|
|
110
|
+
crop,
|
|
111
|
+
flip,
|
|
112
|
+
flop,
|
|
113
|
+
grayscale,
|
|
114
|
+
info,
|
|
115
|
+
negate,
|
|
116
|
+
resize,
|
|
117
|
+
rotate,
|
|
118
|
+
sharpen,
|
|
119
|
+
thumbnail,
|
|
120
|
+
tint
|
|
121
|
+
};
|
package/package.json
ADDED
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "peasy-image",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "Image processing library for Node.js — resize, crop, convert, compress, filter. Powered by sharp.",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"main": "dist/index.js",
|
|
7
|
+
"types": "dist/index.d.ts",
|
|
8
|
+
"exports": {
|
|
9
|
+
".": {
|
|
10
|
+
"import": "./dist/index.js",
|
|
11
|
+
"types": "./dist/index.d.ts"
|
|
12
|
+
}
|
|
13
|
+
},
|
|
14
|
+
"files": [
|
|
15
|
+
"dist"
|
|
16
|
+
],
|
|
17
|
+
"scripts": {
|
|
18
|
+
"build": "tsup src/index.ts --format esm --dts",
|
|
19
|
+
"test": "vitest run",
|
|
20
|
+
"typecheck": "tsc --noEmit"
|
|
21
|
+
},
|
|
22
|
+
"keywords": [
|
|
23
|
+
"image",
|
|
24
|
+
"resize",
|
|
25
|
+
"crop",
|
|
26
|
+
"convert",
|
|
27
|
+
"compress",
|
|
28
|
+
"sharp",
|
|
29
|
+
"peasy"
|
|
30
|
+
],
|
|
31
|
+
"author": "Peasy Tools",
|
|
32
|
+
"license": "MIT",
|
|
33
|
+
"repository": {
|
|
34
|
+
"url": "https://github.com/peasytools/peasy-image-js.git"
|
|
35
|
+
},
|
|
36
|
+
"homepage": "https://peasyimage.com",
|
|
37
|
+
"dependencies": {
|
|
38
|
+
"sharp": "^0.33"
|
|
39
|
+
},
|
|
40
|
+
"devDependencies": {
|
|
41
|
+
"@types/node": "^25.4.0",
|
|
42
|
+
"tsup": "^8.0",
|
|
43
|
+
"typescript": "^5.7",
|
|
44
|
+
"vitest": "^3.0"
|
|
45
|
+
}
|
|
46
|
+
}
|