Thanks to visit codestin.com
Credit goes to github.com

Skip to content

fix(frame): keep the offset on the frame - #127

Merged
olivervogel merged 1 commit into
Intervention:developfrom
nlemoine:fix/frame-offsets
Sep 9, 2026
Merged

fix(frame): keep the offset on the frame#127
olivervogel merged 1 commit into
Intervention:developfrom
nlemoine:fix/frame-offsets

Conversation

@nlemoine

@nlemoine nlemoine commented Sep 9, 2026

Copy link
Copy Markdown
Contributor

Frame::setOffset() has no effect with the vips driver, and offsetTop() reports the extract origin on animations:

$frame = $image->core()->frame(0);
$frame->setOffset(11, 22);
$frame->offsetLeft(); // 0

$image->core()->frame(1)->offsetTop(); // -15 on a 20x15 animation, GD and Imagick say 0

setOffsetLeft() and setOffsetTop() used set('xoffset', ...), which stores a meta item of that name. xoffset and yoffset are header properties, and get() reads the property first, so the meta item is never seen. The write also went to the vips image in place, and for a single-frame core frame() hands out the core's own image.

The header properties are no home for the offset anyway. They are libvips pipeline bookkeeping: crop, extract_area, flip or rotate overwrite them with values of their own, which is where the -15 comes from (Core::frame() extracts with extract_area()), and no encoder writes them out. The offset now lives on the frame as two properties, like the GD driver does, and the vips image is left alone. Nothing in the driver reads frame offsets, so this only changes what the public getters report.

Frame::setOffsetLeft() and setOffsetTop() stored the offset with set(),
which puts a meta item of that name on the vips image. xoffset and
yoffset are header properties though, and get() reads the property
first, so offsetLeft() and offsetTop() kept returning 0 after a set.
The write also went to the vips image in place, and for a single-frame
core that image is the core's own.

The header properties are no home for the offset anyway: crop,
extract_area, flip or rotate overwrite them with values of their own,
and no encoder writes them out. Core::frame() extracts with
extract_area(), so every frame past the first reported the negated
extract origin as its offset, where GD and Imagick report 0. Keep the
offset on the frame as the GD driver does, and leave the vips image
alone.
@olivervogel

Copy link
Copy Markdown
Member

Thanks.

@olivervogel
olivervogel merged commit 63a921f into Intervention:develop Sep 9, 2026
6 checks passed
olivervogel pushed a commit that referenced this pull request Sep 9, 2026
Frame::setOffsetLeft() and setOffsetTop() stored the offset with set(),
which puts a meta item of that name on the vips image. xoffset and
yoffset are header properties though, and get() reads the property
first, so offsetLeft() and offsetTop() kept returning 0 after a set.
The write also went to the vips image in place, and for a single-frame
core that image is the core's own.

The header properties are no home for the offset anyway: crop,
extract_area, flip or rotate overwrite them with values of their own,
and no encoder writes them out. Core::frame() extracts with
extract_area(), so every frame past the first reported the negated
extract origin as its offset, where GD and Imagick report 0. Keep the
offset on the frame as the GD driver does, and leave the vips image
alone.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants