Skip to content

Commit 0782797

Browse files
committed
tidy the changelog and migration guide
1 parent 48665d0 commit 0782797

2 files changed

Lines changed: 19 additions & 14 deletions

File tree

‎CHANGELOG.md‎

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
Upgrading from 3.x? Upgrade to the latest 3.x release first, fix the deprecation hints, then switch: the [migration guide](https://imagescript.dev/documents/Migrating_to_4.0.html) lists every change and the nine behavior changes that don't show up as deprecations or compile errors.
88

99
- **Methods that take options refuse anything else than an object**: a stray number, string, boolean or `null` as the options of `cropCircle()`, `Image.renderText()`, the encoders (`encodeWebP()`, `encodeAVIF()`, `encodeJXL()`, ...), `quantize()`, `transform()`, `dropShadow()`, `outline()`, the gradients, `Image.decode()`, the animation encoders, and `new GainMap()` throws a `TypeError` that names the working form (e.g. `cropCircle({ size: 'cover' })`), so the 3.x calls that are gone like `cropCircle(true)` or `Image.renderText(font, 32, 'Hi')` fail instead of being ignored. Only the type of the argument is checked: a key that isn't an option is still ignored, so a typo like `{ maxWith: 300 }` isn't caught.
10+
1011
- **The mode constants are removed, modes are plain strings**: `Image.RESIZE_*`, `Image.SVG_MODE_*`, `Frame.DISPOSAL_*` and the `ResizeModes`, `SVGScaleModes` and `FrameDisposalModes` classes are gone. Resize modes are `'nearest-neighbor'`, `'bilinear'`, `'bicubic'` and `'area'` (the `ResizeMode` type), disposal modes `'any'`, `'keep'`, `'previous'` and `'background'` (`FrameDisposalModeName`), and the SVG modes became options of `renderSVG()` (below). `Image.RESIZE_AUTO`/`ResizeModes.AUTO` is `image.resize({ width: 256 })`. The old values are no longer accepted either: `'RESIZE_BILINEAR'`, the numbers 1-3 for SVG scale modes and the numeric disposal ids 0-3.
1112

1213
- **`absolute` is removed from `opacity()`, `red()`, `green()`, `blue()`, `lightness()` and `saturation()`**: they only scale now, `image.red(0.5)` (and `AdjustOptions`, the type of their options, is removed). For a fixed color, use `image.recolor()`. In JavaScript a leftover `image.red(0.5, true)` scales the channel instead of setting it.
@@ -83,7 +84,7 @@ Upgrading from 3.x? Upgrade to the latest 3.x release first, fix the deprecation
8384

8485
- **An animation has its own canvas size**: decoded animations keep the file's, `new Animation(frames, { width, height })` sets one, and `resize()` sets the new one. Without one it is the frames' extent, as before. Frames (or their parts) outside the canvas aren't encoded.
8586

86-
- **The encoders return `Promise<Uint8Array<ArrayBuffer>>`**, which `new Blob()`, `new Response()` and `crypto.subtle` take without a cast in TypeScript 5.9 and newer (needs TypeScript 5.7).
87+
- **The encoders return `Promise<Uint8Array<ArrayBuffer>>`** instead of `Promise<Uint8Array>`, so `new Blob()`, `new Response()` and `crypto.subtle` take the output without a cast, also with the stricter DOM types of TypeScript 5.9 and newer. The type needs TypeScript 5.7 or newer.
8788

8889
### New
8990

@@ -93,7 +94,7 @@ Upgrading from 3.x? Upgrade to the latest 3.x release first, fix the deprecation
9394
- `Colors.gradient()` takes an array of evenly spaced colors, like the `stops` of the gradient functions.
9495
- `Animation.scale()`, `Animation.trim()`, `Animation.rotate()`, `Animation.transform()`, `Animation.dropShadow()` and `Animation.outline()`. `scale()` and `trim()` keep the frames; the others work on the composited animation (full canvas frames) and resize the canvas.
9596
- `Frame.contain()`, `Frame.cover()`, `Frame.rotate()`, `Frame.transform()`, `Frame.dropShadow()` and `Frame.outline()`, which move the offsets like `Frame.resize()` and `Frame.crop()`.
96-
- `Image.encodeGIF()` for single images, with `colors`, `dither` and `ditherStrength` (also on the animation encoders).
97+
- `Image.encodeGIF()` for single images, with `colors`, `dither` and `ditherStrength` (also on the animation encoders), and the `DitherMethod` type that `quantize()` and the GIF encoders share.
9798
- `renderSVG({ fonts })` takes a single font without an array.
9899

99100
## 3.20.1

‎guides/Migrating to 4.0.md‎

Lines changed: 16 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -97,9 +97,9 @@ new Animation(frames, { loopCount: Infinity });
9797
animation.loopCount === Infinity;
9898
```
9999

100-
The finite counts are the same: `0` plays once, `2` plays three times. The valid values are `Infinity` and integers from
101-
0 ({@link AnimationOptions.loopCount}). `-1` throws a `RangeError`, like other negative numbers, `NaN` and fractions. Numeric strings, `null` and booleans
102-
throw a `TypeError`. The check applies to the constructor, to the setter `animation.loopCount = ...` (which keeps the
100+
The finite counts are the same: `0` plays once, `2` plays three times. The valid values are `Infinity` and integers
101+
from 0 ({@link AnimationOptions.loopCount}). `-1` throws a `RangeError`, like other negative numbers, `NaN` and
102+
fractions. Numeric strings, `null` and booleans throw a `TypeError`. The check applies to the constructor, to the setter `animation.loopCount = ...` (which keeps the
103103
old count when it throws), and to the encoders `Animation.gifEncoder()`, `webpEncoder()` and `apngEncoder()`.
104104

105105
The formats store a finite count in fixed-size fields: a GIF up to `65535`, a WebP up to `65534` and an APNG up to
@@ -178,9 +178,10 @@ scaled them. Now:
178178
- `frame.rotate(angle)` keeps the frame's middle in place.
179179
- `frame.cover(w, h)` scales the offsets and then moves them by the cropped amount.
180180

181-
`transform()`, `dropShadow()` and `outline()` moved the offsets in 3.x too, but only as far as they allowed (a frame at
182-
`xOffset: 0` grew to the right instead). Now the offsets can become negative: the frame grows evenly, and the part
183-
outside the animation's canvas isn't encoded.
181+
`transform()`, `dropShadow()` and `outline()` moved the offsets in 3.x too, but only as far as they allowed: a frame at
182+
`xOffset: 0` couldn't grow to the left, so a shadow or outline was cut off on that side and a transform grew to the
183+
right instead. Now the frame grows the same way an image does and the offsets can become negative; the part outside the
184+
animation's canvas isn't encoded.
184185

185186
To keep a frame's offsets as they are, call the method on its image: `frame.image.crop(x, y, w, h)`. See
186187
[frames hold an image](#frames-hold-an-image) for the other frame changes.
@@ -264,8 +265,8 @@ for (let i = 0; i < image.bitmap.length; i += 4) image.bitmap[i] = 0.5 * 255;
264265
```
265266

266267
`bitmap` is RGBA, four bytes per pixel. Writing it directly skips the gain map of an HDR image, so do not use it on
267-
images that have one. `absolute` on `lightness()` and `saturation()` sets the value of every pixel and keeps its hue. Do it per pixel:
268-
read the color with `Colors.toHSLA()`, set the lightness or saturation, and write the pixel back with
268+
images that have one. `absolute` on `lightness()` and `saturation()` sets the value of every pixel and keeps its hue.
269+
Do it per pixel: read the color with `Colors.toHSLA()`, set the lightness or saturation, and write the pixel back with
269270
`Colors.fromHSLA()`.
270271

271272
### Animations and GIF
@@ -333,7 +334,7 @@ object under the names of their options. The options of each method are on its o
333334
| `image.dominantColor(true, true, 15)` | `image.dominantColor({ ignoreBlack: true, ignoreWhite: true, threshold: 15 })` |
334335
| `image.roundCorners(8)` | `image.roundCorners({ radius: 8 })` |
335336
| `image.fisheye(3)` | `image.fisheye({ strength: 3 })` |
336-
| `image.trim(color, options)`, `frame.trim(color, options)` | `image.trim({ color, ...options })` |
337+
| `image.trim(color, options)`, `frame.trim(color, options)` | `image.trim({ color, ...options })`, `frame.trim({ color, ...options })` |
337338
| `image.colorToAlpha(color, options)` | `image.colorToAlpha({ color, ...options })` |
338339
| `image.encodePNG(1, { author })` | `image.encodePNG({ compression: 1, metadata: { author } })` |
339340
| `image.encodePNG({ author })` (metadata alone) | `image.encodePNG({ metadata: { author } })`. The old form is ignored, see below |
@@ -402,8 +403,8 @@ The methods that change the size stay on the frame: `resize()`, `scale()`, `cont
402403
animation (resizing scales the offsets, as if the whole animation was resized); see
403404
[frames move their offsets](#frames-move-their-offsets-when-their-size-changes) for how that differs from 3.x.
404405
`width`, `height`, `clone()` and `toString()` work as before. Everything else goes through `frame.image`. The image's
405-
own methods don't know about the frame and leave the offsets alone, so `frame.image.rotate(90)` turns the frame around
406-
its top left corner.
406+
own methods don't know about the frame and leave the offsets alone: after `frame.image.rotate(90)`, the frame's top
407+
left corner stays where it was, and the turned image hangs from it.
407408

408409
### Checked values and the canvas
409410

@@ -474,9 +475,12 @@ grep -rnE '\.(contain|fit)\(|greyscale|drawBox|drawCircle|SVGScaleMode|TextLayou
474475
grep -rnE 'fromHSLA?\(|toHSLA\(|\.rotate\(|renderSVG\([^)]*(size|mode)|layout:|getRGBAAt|\.region\(' src
475476
grep -rnE 'encodeGIF\(|gifEncoder\(|GIFEncodeOptions|encodeJPEG\(' src
476477

477-
# frames: anything an Image does, on a frame
478+
# frames: anything an Image does, on a frame, and the size changes that move the offsets now
478479
grep -rnE 'new Frame\(|Frame\.from\(|frame\w*\.[a-zA-Z]+\(' src
479480

481+
# behavior changes without a compile error
482+
grep -rnE '\.(rotate|quantize|contain|encodeJPEG)\(|from(HSLA?)\(|toHSLA\(' src
483+
480484
# GainMap
481485
grep -rnE 'gainMap\.encode\(|\.encode\(\s*[0-9]' src
482486
```

0 commit comments

Comments
 (0)