@gmitch215/tinyimg 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 +141 -10
- package/dist/image.d.ts +116 -2
- package/dist/image.d.ts.map +1 -1
- package/dist/image.js +222 -8
- package/dist/image.js.map +1 -1
- package/dist/index.d.ts +3 -3
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -1
- package/dist/index.js.map +1 -1
- package/dist/text.js +1 -1
- package/dist/text.js.map +1 -1
- package/dist/tinyimg.wasm +0 -0
- package/dist/transform.d.ts +7 -0
- package/dist/transform.d.ts.map +1 -1
- package/dist/transform.js +104 -14
- package/dist/transform.js.map +1 -1
- package/dist/types.d.ts +166 -5
- package/dist/types.d.ts.map +1 -1
- package/dist/types.js +9 -1
- package/dist/types.js.map +1 -1
- package/dist/wasm.d.ts +58 -0
- package/dist/wasm.d.ts.map +1 -1
- package/dist/wasm.js +22 -4
- package/dist/wasm.js.map +1 -1
- package/package.json +6 -6
package/README.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# 🏞️ tinyimg
|
|
2
2
|
|
|
3
|
-
> Lightweight & fast image processing library for
|
|
3
|
+
> Lightweight & fast image processing library for WebAssembly
|
|
4
4
|
|
|
5
5
|
tinyimg decodes, transforms, draws on and re-encodes images inside a Worker, with no binding, no
|
|
6
6
|
subrequest and no per-transformation charge. It is freestanding C compiled to one wasm32 module,
|
|
@@ -172,9 +172,15 @@ half the time. Across twelve JPEGs, milliseconds per megapixel spread 7.1x while
|
|
|
172
172
|
megabyte spread 1.95x at this scale. The practical rule for a 200 px thumbnail is roughly **480 KB of
|
|
173
173
|
compressed source**, whatever its dimensions.
|
|
174
174
|
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
175
|
+
`decide().estimateMs` covers decode and resample and leaves the encoder out. On 878 held-out cells
|
|
176
|
+
timed against the v1.1.1 model (one machine, sources with alpha excluded) it ran a median 2.0x under
|
|
177
|
+
the clock, 38.6% of cells landed within 0.6x to 2.0x, and the worst was 10.97x under. Adding the
|
|
178
|
+
encoder, which is what `budgetMs` compares against, moved the median to 1.3x under and 59.8% in
|
|
179
|
+
band, with the worst at 9.04x under (a JPEG source) and 7.44x over (a PNG). AVIF sources were the
|
|
180
|
+
worst group, 3.7% in band. The model in this release prices the compressed bytes as well as the
|
|
181
|
+
samples and carries a calibrated upper bound, described under [Admission](#admission). Treat
|
|
182
|
+
`budgetMs` as a coarse guard with no guarantee behind it. Past the ceiling the artifact has to be computed
|
|
183
|
+
once and cached; see [Caching](#caching).
|
|
178
184
|
|
|
179
185
|
A progressive JPEG is the exception worth knowing about. At an eighth scale the transform reads the
|
|
180
186
|
DC term alone, so the scans that carry only high-frequency detail are stepped over rather than
|
|
@@ -190,13 +196,16 @@ the per-stage profile and the comparison against `@jsquash`.
|
|
|
190
196
|
|
|
191
197
|
### Gaps
|
|
192
198
|
|
|
193
|
-
- **AVIF encode has no partition search.** Decode
|
|
199
|
+
- **AVIF encode has no partition search.** Decode reads AV1 intra. The
|
|
194
200
|
encoder uses fixed 8x8 blocks and picks the luma mode from four candidates by absolute
|
|
195
201
|
difference, so its files run 1.1x to 1.3x libaom's size at matched quality. A partition search is
|
|
196
202
|
where most of AV1's compression lives.
|
|
197
203
|
- **No 10 or 12 bit AVIF.** The reconstruction is 8 bits a sample end to end, so an HDR AVIF is
|
|
198
204
|
refused rather than truncated. 4:2:2 is refused too, for a reason in the format: the
|
|
199
205
|
specification's own subsampled-size table has no answer for a tall block on such a plane.
|
|
206
|
+
- **Some AVIF files are refused rather than decoded wrong.** Film grain, superres, `grid` and
|
|
207
|
+
`iovl` images, a cropping `clap` aperture, PQ and HLG transfer, and an alpha plane the decoder
|
|
208
|
+
cannot read each return an unsupported-variant error.
|
|
200
209
|
- **No animation.** Both decode a first frame; neither re-times or composes one.
|
|
201
210
|
- **You own the caching.** Images caches derivatives at the edge as a product feature. tinyimg gives
|
|
202
211
|
you the key and leaves the cache to you; see [Caching](#caching).
|
|
@@ -298,12 +307,18 @@ carry `.bytes()`, `.blob()`, `.response()` and `.dataUrl()`.
|
|
|
298
307
|
| `format` | `ImageFormat` | Container to encode as. Defaults to the source's own. |
|
|
299
308
|
| `quality` | `number` | 1 through 100, for a lossy format. |
|
|
300
309
|
| `lossless`, `progressive` | `boolean` | Where the format has the mode. |
|
|
301
|
-
| `metadata` | `'keep' \| 'none'` |
|
|
310
|
+
| `metadata` | `'keep' \| 'none'` | Accepted, but a transformation writes no EXIF either way. |
|
|
302
311
|
|
|
303
312
|
The options apply in a fixed order, exported as `TRANSFORM_ORDER`: crop, resize or fit, rotate, flip,
|
|
304
313
|
the color adjustments, blur, sharpen, trim. An option object has no order of its own, so two callers
|
|
305
314
|
writing the same keys get the same image.
|
|
306
315
|
|
|
316
|
+
A JPEG with an EXIF orientation, or an AVIF with `irot` and `imir` properties, is turned upright before anything else runs, so `width`, `height`,
|
|
317
|
+
`crop` and `fit` all read the image as displayed. A phone photo stored landscape and tagged 90
|
|
318
|
+
degrees comes out portrait, and a request for 400 wide is a portrait 400 wide. `probe` reports the
|
|
319
|
+
tag as `orientation`, and the chainable API applies it with `Image.autoOrient()`, which has to be
|
|
320
|
+
the first operation. Only JPEG and AVIF report it; every other format reports 1.
|
|
321
|
+
|
|
307
322
|
### Fit Modes
|
|
308
323
|
|
|
309
324
|
| Mode | Absorbs the mismatch by | Scale may |
|
|
@@ -351,6 +366,11 @@ it, call `dispose()` in a `finally`. Encoding does not consume the plan.
|
|
|
351
366
|
|
|
352
367
|
`pixels()` hands back the raw samples for a caller who wants them rather than a container.
|
|
353
368
|
|
|
369
|
+
`edit(fn)` runs after the plan, like `trim` and `rotateFree`, and hands `fn` the materialized image as
|
|
370
|
+
RGBA to change in place. It is for per-pixel arithmetic the library does not carry, such as another
|
|
371
|
+
library's exact blend or a fixed convolution kernel. The extent and channel count cannot change, and
|
|
372
|
+
the view is valid only inside the call.
|
|
373
|
+
|
|
354
374
|
## The Planner
|
|
355
375
|
|
|
356
376
|
Nothing runs until the output is asked for. Operations append to a fixed-capacity list, and the plan
|
|
@@ -390,13 +410,19 @@ On that chain the planner is worth 3.63x against running the same operations one
|
|
|
390
410
|
| ------ | ------------------------------------------------------------------------------- | ----------------------------------------------------------------- |
|
|
391
411
|
| PNG | 8 and 16 bit, gray/palette/truecolor with and without alpha, Adam7 | hash-chain LZ77, static and dynamic Huffman, the five filters |
|
|
392
412
|
| JPEG | baseline and progressive, 4:4:4 / 4:2:2 / 4:2:0, CMYK and YCCK, restart markers | quality-scaled tables, optimized Huffman, progressive scan script |
|
|
393
|
-
| WebP | VP8 lossy and VP8L lossless | both modes
|
|
413
|
+
| WebP | VP8 lossy and VP8L lossless | both modes, alpha kept through an `ALPH` chunk when lossy |
|
|
394
414
|
| GIF | LZW, local and global palettes, interlace, transparency | median-cut palette with Floyd-Steinberg dithering |
|
|
395
415
|
| TIFF | strips, uncompressed / PackBits / LZW / Deflate, both byte orders | uncompressed and PackBits |
|
|
396
416
|
| BMP | uncompressed and RLE8 | uncompressed |
|
|
397
417
|
| AVIF | AV1 intra: every transform, all 13 intra modes, deblock and CDEF | fixed 8x8 partitions, no rate-distortion search |
|
|
398
418
|
| HEIF | container only; `probe` answers and decode reports a specific error | no |
|
|
399
419
|
|
|
420
|
+
A lossy WebP with transparency is written as a `VP8X` header, an `ALPH` chunk holding the alpha plane
|
|
421
|
+
as a lossless stream, and the lossy frame, so alpha is exact at any `quality`; an image whose alpha
|
|
422
|
+
is all 255 gets the plain frame. The JPEG and AVIF encoders write no alpha, and GIF keeps one bit of
|
|
423
|
+
it. When a `transform` output has transparency its format cannot carry, `degraded` contains
|
|
424
|
+
`'alpha'`.
|
|
425
|
+
|
|
400
426
|
JPEG carries true DCT-domain scaled decode at 1/2, 1/4 and 1/8, and region decode that Huffman-scans
|
|
401
427
|
past blocks outside the box without transforming them. PNG, GIF, TIFF and BMP row-skip and
|
|
402
428
|
column-skip.
|
|
@@ -726,9 +752,9 @@ const result = await transform(tinyimg, source, {
|
|
|
726
752
|
result.format; // 'webp' if it fits inside 7 ms, otherwise 'jpeg'
|
|
727
753
|
```
|
|
728
754
|
|
|
729
|
-
A format you name is never substituted, however far over budget it is.
|
|
730
|
-
|
|
731
|
-
it, and use [`measure`](#work-counters) when you need what a request cost.
|
|
755
|
+
A format you name is never substituted, however far over budget it is. On the machine its rates were
|
|
756
|
+
measured on, the estimate's median decode error on images held out of the fit is within 10% for every
|
|
757
|
+
format except TIFF (54% under), the encoder is priced separately, and single requests spread wider, so give a budget below the limit rather than at it, and use [`measure`](#work-counters) when you need what a request cost.
|
|
732
758
|
|
|
733
759
|
**A budget the container change cannot meet degrades the plan, and the result says what it gave up.**
|
|
734
760
|
Container first, because a cheaper encoder costs bytes and nothing else; then the planner's own
|
|
@@ -761,6 +787,108 @@ The output extent never changes. A budget decides how the pixels are made, not h
|
|
|
761
787
|
is degraded when the estimate already fits. `degraded` is empty on a pass-through, which needs no
|
|
762
788
|
lever at all.
|
|
763
789
|
|
|
790
|
+
### Admission
|
|
791
|
+
|
|
792
|
+
Naming `admission` beside `budgetMs` turns the budget into a decision on the calibrated upper bound
|
|
793
|
+
instead of the point estimate. `'strict'` throws `TinyImgBudgetError`, carrying the numbers, when the
|
|
794
|
+
bound plus the encoder is over budget, and gives nothing up. `'degrade'` takes the ladder above,
|
|
795
|
+
judged on the bound, and runs the cheapest request that results. `'passthrough'` degrades the same
|
|
796
|
+
way and returns the source bytes unchanged, with `'passthrough'` in `degraded`, when no rung fits;
|
|
797
|
+
that needs the output format to be the source's own, or none asked for.
|
|
798
|
+
|
|
799
|
+
```ts
|
|
800
|
+
const result = await transform(tinyimg, source, {
|
|
801
|
+
width: 200,
|
|
802
|
+
budgetMs: 10,
|
|
803
|
+
admission: 'passthrough',
|
|
804
|
+
platformScale: 1.9
|
|
805
|
+
});
|
|
806
|
+
```
|
|
807
|
+
|
|
808
|
+
An admitted request also stops itself. The module sums the work its decoders and encoders have
|
|
809
|
+
counted into a work clock, a function of the counters and not of a timer, because a Worker's timers
|
|
810
|
+
do not advance during CPU work. When the clock passes the budget, the operation returns
|
|
811
|
+
`TINYIMG_ERR_BUDGET`, which `transform` throws as `TinyImgBudgetError`, or answers with the source
|
|
812
|
+
under `'passthrough'`. `Image.admit(budgetMs, options)` returns the decision without running
|
|
813
|
+
anything.
|
|
814
|
+
|
|
815
|
+
The bound is a calibrated prediction under exchangeability, not a guarantee. It is relative to the
|
|
816
|
+
machine the cost model was timed on, so `platformScale` carries your own factor; a Worker ran the same
|
|
817
|
+
module 1.9x slower at the median and 2.4x to 4.7x slower on cheap requests, and the library applies
|
|
818
|
+
none. Leaving `admission` unset keeps `budgetMs` exactly as described above.
|
|
819
|
+
|
|
820
|
+
How it held on 423 requests the model never saw, at five budgets from 5 to 100 ms (2,115 request and
|
|
821
|
+
budget pairs, timed on the Apple M2 Pro the model was calibrated on): the bound admitted 739 pairs
|
|
822
|
+
and 67 of them, 9.07%, ran over budget. The v1.1.1 estimate admitted 1,174 and 451 of them, 38.42%,
|
|
823
|
+
ran over, so the bound admits with 6.73x fewer overruns. It misses the 5% overrun rate set for it
|
|
824
|
+
before the run, so use it as a filter and not as a limit. AVIF sources are the weak spot: 26 of the
|
|
825
|
+
32 pairs admitted for them ran over. The other formats together ran over on about 6%. The bound also
|
|
826
|
+
refuses requests that fit, 7.31% of the pairs that did (WebP sources 33.9%). The test left out
|
|
827
|
+
sources with alpha, and lossy WebP with alpha and TIFF encode are priced less tightly (held-out
|
|
828
|
+
coverage 0.82 and 0.89). The tables are in `bench/baselines/v1.2/admission-summary.md`.
|
|
829
|
+
|
|
830
|
+
### Selection
|
|
831
|
+
|
|
832
|
+
`Image.select(options)` searches the decode levers (scale, filter, effort), the output format and its
|
|
833
|
+
quality together, drops each combination that breaks a limit, and returns the best of the rest. It
|
|
834
|
+
reads no pixels and no clock. `Image.bytesFor(selection)` runs the choice and returns the encoded bytes.
|
|
835
|
+
|
|
836
|
+
```ts
|
|
837
|
+
using image = await Image.open(tinyimg, source);
|
|
838
|
+
image.resize(400, 300);
|
|
839
|
+
|
|
840
|
+
const selection = image.select({ budgetMs: 20, platformScale: 1.9, minDb: 35 });
|
|
841
|
+
|
|
842
|
+
if (selection.feasible) {
|
|
843
|
+
const bytes = await image.bytesFor(selection);
|
|
844
|
+
// serve bytes as selection.choice.format
|
|
845
|
+
} else {
|
|
846
|
+
// selection.reason names the check the nearest miss failed
|
|
847
|
+
}
|
|
848
|
+
```
|
|
849
|
+
|
|
850
|
+
| Option | Default | Meaning |
|
|
851
|
+
| ----------------- | ------------------------------- | ----------------------------------------------------------------- |
|
|
852
|
+
| `budgetMs` | no limit | CPU the request may spend, judged on the calibrated upper bound |
|
|
853
|
+
| `platformScale` | `1` | How much slower your machine is than the calibrated one |
|
|
854
|
+
| `peakBytes` | the module's heap ceiling | Largest heap bound a candidate may have |
|
|
855
|
+
| `minDb` | no floor | Predicted PSNR against the undegraded output, in dB |
|
|
856
|
+
| `formats` | the source's own, JPEG and WebP | Output containers to consider |
|
|
857
|
+
| `objective` | `'bytes'` | `'bytes'`, `'time'` or `'quality'`, among the candidates that fit |
|
|
858
|
+
| `uncharacterized` | `'refuse'` | `'allow'` keeps a candidate whose quality is unknown |
|
|
859
|
+
| `assumeOpaque` | `false` | Treat an RGBA source as opaque, so JPEG, AVIF and GIF qualify |
|
|
860
|
+
|
|
861
|
+
A `Selection` carries `feasible`, `reason`, `choice` (format, quality, whether it is lossless, the
|
|
862
|
+
lattice position `bytesFor` runs, and the predicted upper-bound cost, peak heap, dB and bytes), the
|
|
863
|
+
output `width` and `height`, whether the source counted as having `alpha`, the measured `coverage` of
|
|
864
|
+
each table, and every candidate in `considered` with the check that removed it. An infeasible
|
|
865
|
+
selection is a normal answer.
|
|
866
|
+
|
|
867
|
+
On the held-out test images at 10, 20 and 50 ms, with and without a 35 dB floor, the joint search
|
|
868
|
+
served 37.8% of 1,137 requests, the planner's own ladder 17.2% and format-and-quality chosen
|
|
869
|
+
independently 33.8%. Against independent choice the gain is 4 points, interval 3.0 to 5.1, and all of
|
|
870
|
+
it comes from requests without a quality floor. The tables are in
|
|
871
|
+
`bench/baselines/v1.2/selector-summary.md`.
|
|
872
|
+
|
|
873
|
+
The predictions come from tables measured on other images, so each one has a stated reach:
|
|
874
|
+
|
|
875
|
+
- **`db` is a table percentile.** It composes the fifth percentile of the decode lever with the fifth
|
|
876
|
+
percentile of the encoder. On images held out of the fit the lever table's percentile held for
|
|
877
|
+
89.3% of cells (WebP sources 64.5%) and the encode table's for 94.8%, against a 95% target. Read it
|
|
878
|
+
as a likely floor, not a guarantee; `coverage` reports the figure for your source and format.
|
|
879
|
+
- **`bytes` is a median over 99 opaque images.** On the images the table was fitted on, it ordered
|
|
880
|
+
two formats at the same quality tier correctly in 93.5% of pairs. It cannot say how large this
|
|
881
|
+
image will be: measured bytes over predicted ran from 0.32 to 0.58 at the fifth percentile and
|
|
882
|
+
1.27 to 1.84 at the 95th, by format, at quality 75.
|
|
883
|
+
- **Alpha is priced pessimistically.** The tables come from opaque images, so `db` is low and `bytes`
|
|
884
|
+
leaves out the alpha plane. An RGBA source cannot go to JPEG, AVIF or GIF unless `assumeOpaque` is
|
|
885
|
+
set, and the planner cannot see whether the pixels are opaque.
|
|
886
|
+
- **Lossless TIFF, BMP and WebP outputs have no quality class.** Their error is unmeasured, so
|
|
887
|
+
`'refuse'` drops them, and asking for `formats: ['tiff']` or `['bmp']` returns an infeasible
|
|
888
|
+
selection with reason `'uncharacterized'`. A TIFF or BMP source can still go to JPEG or WebP.
|
|
889
|
+
`uncharacterized: 'allow'` keeps the unclassified candidates with an unknown `db`, which cannot
|
|
890
|
+
satisfy a `minDb`.
|
|
891
|
+
|
|
764
892
|
## Caching
|
|
765
893
|
|
|
766
894
|
A cache hit costs no CPU at all, which is how a request too expensive to serve synchronously still
|
|
@@ -793,6 +921,9 @@ const { work } = await tinyimg.measure(() => transform(tinyimg, source, { width:
|
|
|
793
921
|
work.samplesPerTransform; // 1 at an eighth scale, 4 at a quarter, 64 at full
|
|
794
922
|
work.decodedSamples / work.sourceSamples; // what the reduction was worth
|
|
795
923
|
work.filtered; // macroblocks a region did not skip
|
|
924
|
+
work.entropyBytes; // compressed bytes the decoder read, which a region or progressive 1/8 lowers
|
|
925
|
+
work.encodeProbes; // match candidates a PNG encode compared, the cost `encoded` cannot see
|
|
926
|
+
work.alphaDropped; // samples whose alpha a JPEG, AVIF or GIF encode wrote without it
|
|
796
927
|
```
|
|
797
928
|
|
|
798
929
|
`samplesPerTransform` is the one to read for a scaled decode: a decode transforming whole blocks and
|
package/dist/image.d.ts
CHANGED
|
@@ -1,5 +1,44 @@
|
|
|
1
|
-
import { type Color, type Fit, type FlipAxis, type Gravity, type ImageFormat, type PlanDecision, type RawImage, type ResampleFilter, type Source } from './types.js';
|
|
1
|
+
import { type Admission, type Color, type Fit, type FlipAxis, type Gravity, type ImageFormat, type PlanDecision, type RawImage, type ResampleFilter, type Selection, type Source } from './types.js';
|
|
2
2
|
import { TinyImgModule } from './wasm.js';
|
|
3
|
+
/** What {@link Image.admit} takes beyond the budget. */
|
|
4
|
+
export interface AdmitOptions {
|
|
5
|
+
/**
|
|
6
|
+
* `'degrade'` walks the budget ladder on the upper bound before it rejects; `'strict'` rejects
|
|
7
|
+
* a request that is over as it stands. Defaults to `'degrade'`.
|
|
8
|
+
*/
|
|
9
|
+
mode?: 'strict' | 'degrade';
|
|
10
|
+
/** The container the result is written as, which prices the encoder. Defaults to the source's. */
|
|
11
|
+
format?: ImageFormat;
|
|
12
|
+
/** How much slower this machine is than the calibrated one. Defaults to 1. */
|
|
13
|
+
platformScale?: number;
|
|
14
|
+
/** The encoder's quality, which moves its price for JPEG, WebP and AVIF. */
|
|
15
|
+
quality?: number;
|
|
16
|
+
/** Whether WebP is written lossless, which is dearer to encode. */
|
|
17
|
+
lossless?: boolean;
|
|
18
|
+
/** The encoder's compression level for PNG and TIFF. Defaults to `'auto'`. */
|
|
19
|
+
compression?: EncodeOptions['compression'];
|
|
20
|
+
/** The encoder's effort. Defaults to `'fancy'`. */
|
|
21
|
+
effort?: 'fancy' | 'fast';
|
|
22
|
+
}
|
|
23
|
+
/** What {@link Image.select} takes. */
|
|
24
|
+
export interface SelectOptions {
|
|
25
|
+
/** CPU the request may spend, in milliseconds on the machine it runs on. Omitted means no limit. */
|
|
26
|
+
budgetMs?: number;
|
|
27
|
+
/** How much slower this machine is than the calibrated one. Defaults to 1. */
|
|
28
|
+
platformScale?: number;
|
|
29
|
+
/** Largest heap bound a candidate may have, in bytes. Defaults to the module's heap ceiling. */
|
|
30
|
+
peakBytes?: number;
|
|
31
|
+
/** Quality floor as predicted PSNR in dB against the undegraded output. Omitted means no floor. */
|
|
32
|
+
minDb?: number;
|
|
33
|
+
/** Output containers to consider. Defaults to the source's own, JPEG and WebP. */
|
|
34
|
+
formats?: ImageFormat[];
|
|
35
|
+
/** What to minimize among the candidates that fit. Defaults to `'bytes'`. */
|
|
36
|
+
objective?: 'bytes' | 'time' | 'quality';
|
|
37
|
+
/** What to do with a candidate whose quality is unknown. Defaults to `'refuse'`. */
|
|
38
|
+
uncharacterized?: 'refuse' | 'allow';
|
|
39
|
+
/** Treat an RGBA source as opaque, so the search may pick JPEG, AVIF or GIF. */
|
|
40
|
+
assumeOpaque?: boolean;
|
|
41
|
+
}
|
|
3
42
|
/** What {@link Image.bytes} and its siblings take. */
|
|
4
43
|
export interface EncodeOptions {
|
|
5
44
|
/** Quality for a lossy format, 1 through 100. */
|
|
@@ -137,6 +176,21 @@ export declare class Image {
|
|
|
137
176
|
rotate(degrees: 0 | 90 | 180 | 270): this;
|
|
138
177
|
/** Mirrors along one axis or both. */
|
|
139
178
|
flip(axis?: FlipAxis): this;
|
|
179
|
+
/**
|
|
180
|
+
* Turns the source upright by the orientation its EXIF (JPEG) or its `irot` and `imir`
|
|
181
|
+
* properties (AVIF) name.
|
|
182
|
+
*
|
|
183
|
+
* The decoder returns pixels as stored and a plan's output carries no EXIF block, so an image
|
|
184
|
+
* tagged as rotated would otherwise come out sideways. This appends the flip and turn that
|
|
185
|
+
* orientation stands for, which fold into the output addressing like any other, so it costs no
|
|
186
|
+
* pass. A source with no tag, and every format but JPEG and AVIF, appends nothing.
|
|
187
|
+
*
|
|
188
|
+
* Call it before any other operation: a crop or resize after it works in display coordinates,
|
|
189
|
+
* and one before it would not.
|
|
190
|
+
*
|
|
191
|
+
* @throws Error If an operation has already been appended.
|
|
192
|
+
*/
|
|
193
|
+
autoOrient(): this;
|
|
140
194
|
/**
|
|
141
195
|
* Turns by an arbitrary angle, filling the corners with the background.
|
|
142
196
|
*
|
|
@@ -156,6 +210,18 @@ export declare class Image {
|
|
|
156
210
|
* @param tolerance How far a pixel may differ from the border color and still be trimmed.
|
|
157
211
|
*/
|
|
158
212
|
trim(tolerance?: number): this;
|
|
213
|
+
/**
|
|
214
|
+
* Changes the materialized pixels in place, with a function of your own.
|
|
215
|
+
*
|
|
216
|
+
* **Runs after the plan rather than inside it.** The escape hatch for per-pixel arithmetic the
|
|
217
|
+
* library does not carry, such as another library's exact integer blend or a fixed convolution
|
|
218
|
+
* kernel. The image is widened to RGBA first, so `fn` always sees four channels, and it gets a
|
|
219
|
+
* live view into the module's memory: write to `pixels` and the encoder reads what you wrote.
|
|
220
|
+
* The extent and the channel count cannot change, and the view is only valid inside the call.
|
|
221
|
+
*
|
|
222
|
+
* @param fn Receives the extent and `width * height * 4` bytes, rows tightly packed.
|
|
223
|
+
*/
|
|
224
|
+
edit(fn: (image: RawImage) => void): this;
|
|
159
225
|
/** Scales every channel. 1 is unchanged. */
|
|
160
226
|
brightness(factor: number): this;
|
|
161
227
|
/** Scales every channel about mid gray. 1 is unchanged. */
|
|
@@ -252,8 +318,43 @@ export declare class Image {
|
|
|
252
318
|
* {@link transform}, which does that for you.
|
|
253
319
|
*
|
|
254
320
|
* @param milliseconds The budget, or 0 to remove it.
|
|
321
|
+
* @param basis Which cost the ladder compares to the budget. `'point'`, the default, is the
|
|
322
|
+
* estimate; `'upper'` is the calibrated upper bound, so a rung that fits is one whose bound
|
|
323
|
+
* fits.
|
|
255
324
|
*/
|
|
256
|
-
budget(milliseconds: number): this;
|
|
325
|
+
budget(milliseconds: number, basis?: 'point' | 'upper'): this;
|
|
326
|
+
/**
|
|
327
|
+
* Decides whether this request fits a CPU budget, on the calibrated upper bound.
|
|
328
|
+
*
|
|
329
|
+
* Prices the plan undegraded, adds the encoder for the format being written, and multiplies by
|
|
330
|
+
* `platformScale`. The request is admitted when that bound is within `budgetMs`. In the default
|
|
331
|
+
* `'degrade'` mode an over-budget request walks the planner's ladder on the bound and is
|
|
332
|
+
* `'degraded'` when a rung fits and `'reject'` when none does; `'strict'` rejects without
|
|
333
|
+
* trying. The plan's own {@link budget} is not read and not changed.
|
|
334
|
+
*
|
|
335
|
+
* The bound is a prediction under exchangeability, not a guarantee, and it is relative to the
|
|
336
|
+
* machine the cost model was calibrated on.
|
|
337
|
+
*
|
|
338
|
+
* @param budgetMs CPU the request may spend, in milliseconds on the machine it runs on.
|
|
339
|
+
* @param options The mode, the output format, the machine factor and the encoder's settings.
|
|
340
|
+
* @return The decision and the numbers behind it.
|
|
341
|
+
*/
|
|
342
|
+
admit(budgetMs: number, options?: AdmitOptions): Admission;
|
|
343
|
+
/**
|
|
344
|
+
* Searches the ways to run this request and picks the best one that fits the limits.
|
|
345
|
+
*
|
|
346
|
+
* Crosses the planner's decode levers (scale, filter, effort) with the output format and its
|
|
347
|
+
* quality, drops each combination that breaks a limit, and takes the best by `objective`. It
|
|
348
|
+
* reads no pixels and no clock, so it costs a few table lookups per candidate. Run the choice
|
|
349
|
+
* with {@link bytesFor}.
|
|
350
|
+
*
|
|
351
|
+
* The limits are the options', not the plan's own {@link budget}. A selection with `feasible`
|
|
352
|
+
* false is a normal answer: `reason` names the check the nearest miss failed.
|
|
353
|
+
*
|
|
354
|
+
* @param options The limits and the objective.
|
|
355
|
+
* @return The choice, the predicted figures behind it and every candidate looked at.
|
|
356
|
+
*/
|
|
357
|
+
select(options?: SelectOptions): Selection;
|
|
257
358
|
/**
|
|
258
359
|
* Runs the plan and encodes the result.
|
|
259
360
|
*
|
|
@@ -265,6 +366,19 @@ export declare class Image {
|
|
|
265
366
|
* @return The encoded bytes.
|
|
266
367
|
*/
|
|
267
368
|
bytes(format?: ImageFormat, options?: EncodeOptions): Promise<Uint8Array<ArrayBuffer>>;
|
|
369
|
+
/**
|
|
370
|
+
* Runs the plan the way a {@link select} chose and encodes it as that choice says.
|
|
371
|
+
*
|
|
372
|
+
* Decodes at the lattice point the selection names (its scale, filter and effort) and writes
|
|
373
|
+
* the format, quality and coding it names. `options` supplies the settings the selection does
|
|
374
|
+
* not carry: `progressive`, `stripMetadata`, `effort` and `compression`. The selection has to
|
|
375
|
+
* come from this image, with no operation added since.
|
|
376
|
+
*
|
|
377
|
+
* @param selection A feasible selection from {@link select}.
|
|
378
|
+
* @param options Encoder settings other than quality and lossless.
|
|
379
|
+
* @return The encoded bytes.
|
|
380
|
+
*/
|
|
381
|
+
bytesFor(selection: Selection, options?: Omit<EncodeOptions, 'quality' | 'lossless'>): Promise<Uint8Array<ArrayBuffer>>;
|
|
268
382
|
/**
|
|
269
383
|
* Runs the plan and hands back the raw samples.
|
|
270
384
|
*
|
package/dist/image.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"image.d.ts","sourceRoot":"","sources":["../src/ts/image.ts"],"names":[],"mappings":"AAAA,OAAO,EAGN,KAAK,KAAK,EACV,KAAK,GAAG,EACR,KAAK,QAAQ,EACb,KAAK,OAAO,EACZ,KAAK,WAAW,EAChB,KAAK,YAAY,EACjB,KAAK,QAAQ,EACb,KAAK,cAAc,
|
|
1
|
+
{"version":3,"file":"image.d.ts","sourceRoot":"","sources":["../src/ts/image.ts"],"names":[],"mappings":"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"}
|