Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
189 commits
Select commit Hold shift + click to select a range
d2b1305
remove the RESIZE_*, SVG_MODE_* and DISPOSAL_* constants
matmen Nov 8, 2026
b0523b8
remove the absolute argument of the adjust methods
matmen Nov 8, 2026
8175879
remove Image.encode()
matmen Nov 8, 2026
e01dcc7
remove the color helpers of Image
matmen Nov 8, 2026
183739c
remove Image[Symbol.iterator] and iterateWithColors
matmen Nov 8, 2026
13afda1
remove PNGMetadata
matmen Nov 8, 2026
145a62c
remove the max argument of cropCircle
matmen Nov 8, 2026
e07f362
remove the positional forms of renderText
matmen Nov 8, 2026
df000a4
remove the deprecated animation encoder options and frames
matmen Nov 8, 2026
e0340af
reject arguments that are not options in cropCircle and renderText
matmen Nov 8, 2026
6556b04
remove the positional mode of the resize functions
matmen Nov 8, 2026
1ad99fd
remove the positional arguments of composite and the other image oper…
matmen Nov 8, 2026
ceb2b09
remove the positional arguments of the encoders
matmen Nov 8, 2026
be2a27b
remove the positional arguments of renderSVG
matmen Nov 8, 2026
c539759
remove the positional arguments of Frame and Animation
matmen Nov 8, 2026
d6f3253
reject arguments that are not options in all methods that take options
matmen Nov 8, 2026
8a73778
decode() returns an Animation for files with several frames
matmen Nov 8, 2026
da60e9e
remove the GIF class
matmen Nov 8, 2026
474425a
Animation holds its frames instead of extending Array
matmen Nov 8, 2026
4214502
loop counts are Infinity or a count from 0
matmen Nov 8, 2026
c9ce470
add a migration guide for 4.0
matmen Nov 8, 2026
ec2d056
text alignments only take the values of their own axis
matmen Nov 8, 2026
c6fe4e6
decode() takes options only
matmen Nov 8, 2026
bfa2219
channel methods reject the removed absolute argument
matmen Nov 8, 2026
d6dde6f
resize() needs a height or the options form
matmen Nov 8, 2026
daf8412
share the loop count conversion
matmen Nov 8, 2026
5eff581
refuse loop counts that don't fit the format
matmen Nov 8, 2026
9cc0466
test that Animation.decode returns an Animation for single frames
matmen Nov 8, 2026
e3f4bda
changelog and guide: removed types, exact wording
matmen Nov 8, 2026
0446780
reject arguments that are not options in apngEncoder
matmen Nov 8, 2026
2807fb6
changelog: upgrade to the latest 3.x release first
matmen Nov 8, 2026
e30f5d0
let prereleases use the changelog section of their release
matmen Nov 8, 2026
771cdcd
Image.decode returns the first frame of animations
matmen Nov 8, 2026
2dbd9ef
remove the onlyFirstFrame option
matmen Nov 8, 2026
c235725
return Uint8Array<ArrayBuffer> from the encoders
matmen Nov 8, 2026
8151cd2
add the subsampling option of encodeJPEG
matmen Nov 8, 2026
9bc12c7
spell the API in American English
matmen Nov 8, 2026
2b58720
share the encoder option types
matmen Nov 8, 2026
6d54690
use one DecodeOptions for every decode function
matmen Nov 8, 2026
0337b83
let Colors.gradient take an array of colors
matmen Nov 8, 2026
f47eff2
take and return hues in degrees
matmen Nov 8, 2026
57cbf82
rename the parameters of setPixelAt, lightness and saturation
matmen Nov 8, 2026
5d9fe6b
rename the resize option of rotate to expand
matmen Nov 8, 2026
71479bc
let renderSVG take a width, height or scale
matmen Nov 8, 2026
e45b7e9
take the text layout as plain options
matmen Nov 8, 2026
3edcc57
rename the gain map range to min and max and check the parameters whe…
matmen Nov 8, 2026
12a854e
check frame durations and offsets when set
matmen Nov 8, 2026
e48594f
let contain pad to the box and add the inside fit of resize
matmen Nov 8, 2026
774d987
give animations a canvas and add clone, crop, contain and cover
matmen Nov 8, 2026
3fa8d0a
remove drawBox and drawCircle
matmen Nov 8, 2026
9f36d48
test the reshaped API
matmen Nov 8, 2026
4b1f238
changelog and guide: reshaped API
matmen Nov 8, 2026
fb31240
remove the checks for 3.x calls
matmen Nov 8, 2026
79b048d
replace the mode constant classes with plain strings
matmen Nov 8, 2026
9121d42
rotate clockwise, with the sampling modes of transform
matmen Nov 8, 2026
d5e4ce9
let renderSVG take one font without an array
matmen Nov 8, 2026
d418216
add Image.encodeGIF and replace the GIF quality with colors and dithe…
matmen Nov 8, 2026
9703fb3
remove getRGBAAt
matmen Nov 8, 2026
9013644
take the text layout options at the top level of renderText
matmen Nov 8, 2026
7ce90e8
composite transparent images onto a background when encoding JPEG
matmen Nov 8, 2026
a0bec2b
make Frame hold an image instead of extending Image
matmen Nov 8, 2026
8ff3f51
rename region to extract
matmen Nov 8, 2026
652fa1f
fix typos in the API docs
matmen Nov 8, 2026
71daff8
update the changelog and migration guide
matmen Nov 8, 2026
9bfa152
dither quantize like the GIF encoders by default
matmen Nov 8, 2026
2180106
move frame offsets with every size-changing method and add them to An…
matmen Nov 8, 2026
48665d0
document the frame and animation size changes and the dither defaults
matmen Nov 8, 2026
0782797
tidy the changelog and migration guide
matmen Nov 8, 2026
aa385b4
define DitherMethod once
matmen Nov 9, 2026
d208b6f
rename FrameDisposalModeName, SVGOptions and TextStyle to FrameDispos…
matmen Nov 9, 2026
abd6806
fix: always return Uint8Array<ArrayBuffer>
matmen Nov 9, 2026
53d62d3
feat: test runner parallelism
matmen Nov 9, 2026
784ae83
fix: increase timeout to 2min per test
matmen Nov 9, 2026
e0782ce
Consolidate resize fit modes
matmen Nov 9, 2026
8af89ea
Freeze animation frame snapshots
matmen Nov 9, 2026
7c2a53c
Tighten fixed-length API tuple types
matmen Nov 9, 2026
7b73444
Preserve explicit animation decode signals
matmen Nov 9, 2026
64ab0be
Audit v4 migration documentation
matmen Nov 9, 2026
414f4d6
Fix loop count test timestamp flake
matmen Nov 9, 2026
7db8278
fix: differentiate between ICO and CUR
matmen Nov 10, 2026
bbce672
fix(gainmap): return readonly tuples
matmen Nov 10, 2026
1d2638a
fix(tiff): pass maxPixels to JPEG decoder
matmen Nov 10, 2026
ff82f62
fix(svg): support maxPixels
matmen Nov 10, 2026
6291ef1
rework docs
matmen Nov 10, 2026
4e5fb20
cover all changes in the migration guide
matmen Nov 10, 2026
becd0cc
tests: allow svg DoS test more time
matmen Nov 10, 2026
be0abc8
fix: tighten values, defaults and limits before 4.0
matmen Nov 11, 2026
46ccb9a
refactor: drop dead initial values
matmen Nov 11, 2026
0757c06
chore(deps): eslint 10, patched minimatch and glob
matmen Nov 11, 2026
cf149dc
fix(docs): attach the migration guide to the entry module
matmen Nov 11, 2026
7473942
docs: link the migration guide on GitHub during the release candidates
matmen Nov 11, 2026
8c4339e
ci: read-only token for the test workflow
matmen Nov 11, 2026
1be419d
ci: install Chromium without apt packages
matmen Nov 11, 2026
c8d5266
ci: skip the install scripts of the edge and browser test tools
matmen Nov 11, 2026
f639e7c
ci(coverage): compare branch pushes with the previous push
matmen Nov 11, 2026
44fa44d
chore(deps): typedoc 0.28
matmen Nov 11, 2026
3cbb608
chore(deps): TypeScript 6
matmen Nov 11, 2026
6ba85b8
ci: Vite 8 and Playwright 1.65 for the browser test
matmen Nov 11, 2026
0e8ac8a
chore(bench): @napi-rs/canvas 1.1.0, tinybench 6.2.3
matmen Nov 11, 2026
f71440d
fix(tsconfig): use esnext module system
matmen Nov 11, 2026
2e5421d
chore(license): switch to MIT
matmen Nov 11, 2026
dfb78ad
fix a hang in the SVG rasterizer for shapes far outside the image
matmen Nov 12, 2026
6a5e1b5
limit feTurbulence octaves to 24
matmen Nov 12, 2026
03fca4c
limit nested masks, clip paths, patterns, markers and filter images i…
matmen Nov 12, 2026
f1cd5ff
parse SVG transform lists in linear time
matmen Nov 12, 2026
4a89129
change a frame once when an animation lists it more than once
matmen Nov 12, 2026
6a32b1d
keep the size when rotating by a right angle without expand
matmen Nov 12, 2026
e4b2dcd
cut the frames of the animation encoders to the canvas
matmen Nov 12, 2026
70f2391
reject instead of throw synchronously in AnimationEncoder.add
matmen Nov 12, 2026
10b3c94
write gradients with fractional sizes at the truncated size
matmen Nov 12, 2026
ff774d1
throw for an out-of-range JPEG quality
matmen Nov 12, 2026
f868f33
keep a side at one pixel in scale
matmen Nov 12, 2026
6bc7a9d
check the source of composite
matmen Nov 12, 2026
1d76007
export LimitError
matmen Nov 12, 2026
da38bc3
take maxPixels in GainMap.decode
matmen Nov 12, 2026
995701d
name the values in the gain map's cross checks
matmen Nov 12, 2026
93eeca1
reject a JPEG XL blend alpha channel that doesn't exist
matmen Nov 12, 2026
1089298
accept null for creationTime and software
matmen Nov 12, 2026
6250dcc
document the fixes in the changelog and migration guide
matmen Nov 12, 2026
40ae5d6
state the minimum TypeScript version in the README
matmen Nov 12, 2026
775a2f6
lower the SVG budget for nested masks and patterns
matmen Nov 12, 2026
016a6db
remove the fast option of resize and scale
matmen Nov 12, 2026
6fe1e6b
rename GainMap.encode to encodeJPEG
matmen Nov 12, 2026
ae28894
share DitherOptions and make QuantizeOptions a union
matmen Nov 12, 2026
40f379d
make RenderSVGOptions a union of the sizes
matmen Nov 12, 2026
b31da67
rename the fonts option of renderSVG to font
matmen Nov 12, 2026
21a12be
extend the still image options in the animation encoder options
matmen Nov 12, 2026
a8c5594
add Animation.flip and the FlipDirection type
matmen Nov 12, 2026
79779f8
take the dominantColor threshold in channel values
matmen Nov 12, 2026
0daa9cd
name the opacity parameter factor
matmen Nov 12, 2026
b098bb9
take the image's width and height in renderText
matmen Nov 12, 2026
a47ca18
remove coordinates
matmen Nov 12, 2026
704fb23
document the quarter turns without expand in the migration guide
matmen Nov 12, 2026
6015aa5
document the LimitError constructor
matmen Nov 12, 2026
fd31721
find the dominant color in a color histogram
matmen Nov 12, 2026
02b05f7
drop the LimitError constructor
matmen Nov 12, 2026
cdfe091
make the AnimationEncoder constructor private
matmen Nov 12, 2026
d3dd347
replace the TextLayout class with a function
matmen Nov 12, 2026
7818414
fix the TextLayout redirect and hide the LimitError constructor in th…
matmen Nov 12, 2026
edd908f
check enum options with oneOf
matmen Nov 12, 2026
c17f4ca
check pixel limits and threads in options.ts
matmen Nov 12, 2026
73d888d
check the gain map scale and the dither method with the shared helpers
matmen Nov 12, 2026
17b342c
lint hand-written option checks outside options.ts
matmen Nov 12, 2026
4004104
list the fixes in the changelog
matmen Nov 13, 2026
2a480bc
sample bilinear rotations in 8 bits again
matmen Nov 13, 2026
5168717
document thrown errors, examples and related methods in the doc comments
matmen Nov 13, 2026
cdd6820
run the examples of the doc comments
matmen Nov 13, 2026
38c4a6b
name the render options in the renderSVG size limit error
matmen Nov 13, 2026
40f067e
document the defaults of options with @defaultValue
matmen Nov 13, 2026
251432a
check error types instead of messages
matmen Nov 13, 2026
9caf3af
merge the options object checks into one test
matmen Nov 13, 2026
a2a65c0
remove checks of removed APIs, toString wording and internal helpers
matmen Nov 13, 2026
f562d9b
drop checks that another test already makes
matmen Nov 13, 2026
96b4f73
fix checks that could not fail
matmen Nov 13, 2026
b970ef8
drop comments that narrate old behaviour
matmen Nov 13, 2026
1f36f1f
refuse TIFFs with oversized YCbCr subsampling or sample counts
matmen Nov 13, 2026
b5003b1
clip the crop region of an animation to the canvas
matmen Nov 13, 2026
84d014d
copy the gain map an image is given
matmen Nov 13, 2026
dd583f9
refuse animation canvases GIF can't store or that are empty
matmen Nov 13, 2026
5fbd589
resize animation frames that share an image per size
matmen Nov 13, 2026
5e55603
blend gradients with transparency premultiplied
matmen Nov 13, 2026
a92281f
count all frames of a JPEG XL animation against maxPixels
matmen Nov 13, 2026
aae816f
leave the image and its gain map untouched when fill() or cover resiz…
matmen Nov 13, 2026
84dc4f5
rename the size of cropCircle to fit
matmen Nov 13, 2026
90e4981
refuse negative radius and fisheye strengths that leave nothing
matmen Nov 13, 2026
076e941
reject numbers given as strings or other types
matmen Nov 13, 2026
365c080
keep the whole frames of cut-off animations and refuse GIFs without one
matmen Nov 13, 2026
6057c27
document worker fallbacks and the decode orientation formats
matmen Nov 13, 2026
fbfec41
throw a LimitError for shadows and outlines that exceed the image siz…
matmen Nov 13, 2026
4553d1c
merge the edges that start in a row into the rasterizer's active edges
matmen Nov 13, 2026
2e4d23a
correct the migration note on gain map copies
matmen Nov 13, 2026
ba74b9f
composite decoded animation frames as they are decoded
matmen Nov 14, 2026
cc3daa3
bound the memory of dashed strokes
matmen Nov 14, 2026
d6b7433
drop the incomplete last frame of cut-off animations
matmen Nov 14, 2026
84bf3e2
bound the work of round joins and overlapping strokes in the SVG rast…
matmen Nov 14, 2026
926dfa7
declare sideEffects in the build's package.json
matmen Nov 14, 2026
b9336cd
refuse the values numeric arguments still accepted silently
matmen Nov 14, 2026
74d79bd
size the canvas of Animation.resize() and scale() like Image does
matmen Nov 14, 2026
dd07f0b
report damaged frame headers and sizes as decoding errors
matmen Nov 14, 2026
3ae209d
correct the documentation findings of the release check
matmen Nov 14, 2026
fe79718
merge master (3.20.3) into v4
matmen Nov 14, 2026
847b364
type the gain map channel check for the linter
matmen Nov 14, 2026
1718c94
skip the crossing budget test under coverage
matmen Nov 14, 2026
aa39a89
name the cropCircle fit option in the CHANGELOG
matmen Nov 14, 2026
28290ee
sweep fewer cut points in the cut-off animation test
matmen Nov 14, 2026
f07f889
move the cut-off animation test to a file of its own
matmen Nov 14, 2026
d675d9d
read a composite source that shares the destination's memory first
matmen Nov 14, 2026
e8906a8
reject what the user report found accepted, and document its doc gaps
matmen Nov 14, 2026
bc10e03
add the user report fixes to the CHANGELOG
matmen Nov 14, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 7 additions & 2 deletions .github/workflows/coverage.yml
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
name: coverage

# measures the test coverage (npm run coverage) of every pushed branch and pull requests from forks, and how it
# changed: compared with the commit before the push on master, else with where the branch (or pull request) left
# master, measured in the same job. The job summary shows it; pushes to master get it as a commit comment, pushes to a
# changed, measured in the same job: compared with the commit before the push on master and on branches without a pull
# request (where the branch left master for a new branch or a force push), else with where the branch (or pull request)
# left master. The job summary shows it; pushes to master get it as a commit comment, pushes to a
# branch with a pull request as a comment on it (one, updated by later pushes). Pull requests from forks have no
# write access: only the job summary
on:
Expand Down Expand Up @@ -39,6 +40,8 @@ jobs:
run: |
if [ "$EVENT" = pull_request ]; then base=$(git merge-base "$PR_BASE" HEAD); name="the pull request's base"
elif [ "$REF" = refs/heads/master ]; then base=$BEFORE; name="the previous commit on master"
elif [ -z "$(gh pr list --head "$BRANCH" --state open --json number --jq '.[0].number')" ] && git cat-file -e "$BEFORE^{commit}" 2>/dev/null; then
base=$BEFORE; name="the previous push"
else base=$(git merge-base origin/master HEAD); name="master where the branch left it"; fi
if [ -z "$base" ] || ! git cat-file -e "$base^{commit}" 2>/dev/null || [ "$base" = "$(git rev-parse HEAD)" ]; then
echo "no base to compare with"; exit 0
Expand All @@ -55,6 +58,8 @@ jobs:
REF: ${{ github.ref }}
BEFORE: ${{ github.event.before }}
PR_BASE: ${{ github.event.pull_request.base.sha }}
BRANCH: ${{ github.ref_name }}
GH_TOKEN: ${{ github.token }}
- if: steps.base.outputs.summary
run: node scripts/coverage-report.js "$SUMMARY" "$ROOT"
env:
Expand Down
13 changes: 10 additions & 3 deletions .github/workflows/node.yml
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,10 @@ concurrency:
group: node-${{ github.event_name }}-${{ github.ref }}
cancel-in-progress: ${{ github.event_name != 'release' }}

# the jobs only install, build and test
permissions:
contents: read

jobs:
build:
if: github.event_name != 'pull_request' || github.event.pull_request.head.repo.full_name != github.repository
Expand Down Expand Up @@ -94,7 +98,8 @@ jobs:
node-version: 24.x
- run: npm install
- run: npm run build
- run: npm install --no-save esbuild@0.28.2 miniflare@4.20260730.0 edge-runtime@4.0.1
# (esbuild's and workerd's postinstall scripts only check their binaries, which come with their platform packages)
- run: npm install --no-save --ignore-scripts esbuild@0.28.2 miniflare@4.20260730.0 edge-runtime@4.0.1
- run: node tests/edge/run.mjs

browser:
Expand All @@ -107,6 +112,8 @@ jobs:
node-version: 24.x
- run: npm install
- run: npm run build
- run: npm install --no-save vite@6.4.5 playwright@1.64.1 esbuild@0.28.2
- run: npx playwright install --with-deps chromium
- run: npm install --no-save --ignore-scripts vite@8.3.8 playwright@1.65.0
# (the runner image has the libraries Chromium needs: --with-deps only added fonts through apt, which the tests
# don't use, and failed the job whenever the Ubuntu mirrors were unreachable)
- run: npx playwright install chromium
- run: node tests/browser/run.mjs
157 changes: 155 additions & 2 deletions CHANGELOG.md

Large diffs are not rendered by default.

28 changes: 16 additions & 12 deletions LICENSE
Original file line number Diff line number Diff line change
@@ -1,15 +1,19 @@
This software is licensed under the following license(s):
- GNU AFFERO GENERAL PUBLIC LICENSE, Version 3
- MIT License
Copyright (c) 2020-2026 Mathis Mensing

== SPDX-License-Identifier: AGPL-3.0-or-later OR MIT ==
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

You may choose to comply with either one of the above
mentioned licenses, but a license must be chosen.
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

The corresponding license files can be found in the projects
root directory, prefixed with LICENSE, suffixed with their
corresponding SPDX identifier.

Parts of this software are derived from third party projects under their
own licenses (MIT, Apache-2.0 and the IJG license), see THIRD_PARTY_NOTICES.md.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
Loading
Loading