Repository navigation
Keep declared open-graph image size for images Quarto cannot measure - #15040
Merged
Merged
Conversation
Collaborator
✅ Snyk checks have passed. No issues have been found so far.
💻 Catch issues earlier using the plugins for VS Code, JetBrains IDEs, Visual Studio, and Eclipse. |
This was referenced Oct 13, 2026
cderv
added a commit
that referenced
this pull request
Oct 14, 2026
imageSize only measured files named ".png", so JPEG feed images, listing items and og:image/twitter:image never got a height or width. imageSize now detects PNG and JPEG from the file's header bytes, not its extension, so uppercase ".PNG" and ".jpeg" names are measured too. - Read JPEG dimensions with a small marker scan in src/core/jpeg.ts, with no new dependency. Baseline, progressive and lossless JPEGs are all covered. - Add isPng() in src/core/png.ts, checking the PNG spec signature. - Other formats (SVG, GIF, WebP) still return no size. SVG often has no pixel size, and social platforms reject it as og:image. Related to #12016 and #15040.
With `site-url` set, resolveImageMetadata replaced the declared `image-width`/`image-height` with the size read by imageSize, which only reads PNG. A JPEG social image therefore lost the size the user wrote (#12016), and removing `site-url` only hid it by skipping this path. The measured size now wins when the file can be read, and the declared size is the fallback. Letting the declared size always win would have been simpler, but page metadata is merged with the site's open-graph data: a post that sets its own `image` would inherit the size declared for the site image and emit it for a different file. So a size declared at site level is dropped when the page sets its own image without declaring a size for it. This also removes the inherited size that pages already got without `site-url`. There is no override of a measured size: og:image:width/height describe the image's pixel dimensions, which is what the file reports. Fixes #12016
…red for The previous change dropped the site's declared size when the page sets its own image, but decided ownership too coarsely: - A page declaring only one of image-width/image-height kept the other site dimension, producing a mixed size. Each dimension now comes from the page alone when the page owns the image. - `image: false` counted as a page image, yet mergedSiteAndDocumentData keeps the site image in that case, so the site image lost its size. The check now uses the same truthy predicate as the merge. - A preview image discovered in the page content (.preview-image or a named file) was decided after opengraphMetadata ran, so it inherited the site's declared size. Discovery now applies the same rule. The website.image fallback is still a site image and keeps the site size.
A page with an empty `open-graph:` entry gets null for that key, and typeof null is "object". The object checks in opengraphMetadata and usePageDeclaredImageSize let it through, and reading a property off the null aborted the render on sites whose website.open-graph is an object. Before this branch mergeConfigs ignored the null source, so the site configuration was used without error. Treat null as no page open-graph block, so the site configuration applies as it did before.
cderv
force-pushed
the
fix/issue-12016
branch
from
October 14, 2026 10:49
9de1658 to
751a079
Compare
Since #15050, Quarto measures JPEG images for open-graph metadata, and a measured size wins over a declared one. The site's mark.jpg is 34x52, so the fixtures that use it as the site image now emit 34 and 52 instead of the declared 1200 and 892. The declared-size cases that Quarto cannot measure keep their expectations in post-svg-declared.qmd.
Since #15050 measures JPEG files, the fixtures using the local mark.jpg site image no longer exercise the declared-size fallback at the site level. A remote image is never measured, so with site-url its declared image-width and image-height must still reach og:image:width and og:image:height. This fails on main, where the size is replaced by the undefined measurement.
cderv
added a commit
to quarto-dev/quarto-web
that referenced
this pull request
Oct 14, 2026
The image row described only PNG measurement and suggested JPEG as a case for declared sizes. Since quarto-dev/quarto-cli#15050, Quarto also measures JPEG, so declared sizes only matter for remote images and formats like WebP or GIF. quarto-dev/quarto-cli#15040 also stops a page image from inheriting the sizes declared in website: open-graph. The check is whether the page supplies an image, not whether it differs from the site image, and only the page's open-graph block is read, not top-level image-width/height. Sites without site-url that used the site sizes as defaults lose those tags, so document the migration through page or _metadata.yml open-graph metadata, and note that directory sizes also apply to the site image on pages without their own image. All statements checked by rendering test sites with a 1.11 dev build and with 1.10.19.
#15050 now measures JPEG images, so the original JPEG case from #12016 no longer depends on this change. What remains is keeping a declared size for images Quarto cannot measure, such as remote ones, and limiting a site-declared size to the site image. The second part changes output for sites without site-url that declared a global size because all their page images share it: a page that sets its own image, even the site image again, no longer gets the site size. The entry names where to move the declaration.
cderv
added a commit
to quarto-dev/quarto-web
that referenced
this pull request
Oct 14, 2026
* Document how open-graph image-width and image-height apply The image rows of both social metadata tables said a declared image-width/image-height improves "your Twitter Card". Twitter Card metadata never reads a declared size; only Open Graph does. With site-url set, Quarto measures PNG images and uses that size over a declared one. From Quarto 1.11 (quarto-dev/quarto-cli#15040), a declared size is kept for images Quarto can't measure (JPEG, SVG, ...), and a page that brings its own image no longer inherits the size declared for the site image. Explain both in the Open Graph table, and point the Twitter Card row there instead. * Explain open-graph image size behaviour in its own section The image row described only PNG measurement and suggested JPEG as a case for declared sizes. Since quarto-dev/quarto-cli#15050, Quarto also measures JPEG, so declared sizes only matter for remote images and formats like WebP or GIF. quarto-dev/quarto-cli#15040 also stops a page image from inheriting the sizes declared in website: open-graph. The check is whether the page supplies an image, not whether it differs from the site image, and only the page's open-graph block is read, not top-level image-width/height. Sites without site-url that used the site sizes as defaults lose those tags, so document the migration through page or _metadata.yml open-graph metadata, and note that directory sizes also apply to the site image on pages without their own image. All statements checked by rendering test sites with a 1.11 dev build and with 1.10.19.
3 of 5 tasks
cderv
added a commit
that referenced
this pull request
Oct 14, 2026
Relative image paths for og:image, twitter:image and listing feeds resolved against the wrong directory on pages in subdirectories. The URLs pointed to files that do not exist and lost width and height. Each source now resolves against the file it is written in: site-level images in _quarto.yml against the project, page and metadata images against the document, and feed.image against the project. - Site image, open-graph.image and twitter-card.image become project-relative before they reach the page metadata, so the URL, the size and the copied file all come from the project. - The site and page metadata merge works on a copy, so a page image no longer leaks into the site object shared by all pages. - A listing's own image is joined onto the listing's directory for the feed, using the helper listing item images already used (projectRelativeHref). - The site URL join uses joinUrl, so a site-url ending in / no longer produces a doubled slash. Paths starting with / and URLs are unchanged. Without site-url the value is written as is. The website.image fallback came from #5389 without a base decision. Related to #15040, which edits the same block to keep a declared image size (#12016). Fixes #15039
2 of 5 tasks
cderv
added a commit
that referenced
this pull request
Oct 15, 2026
Remove the top-level `image-width` and `image-height` options, which nothing read. Open Graph sizes come from `open-graph` or from measuring the image. Because the schema typed them as strings, a numeric value such as `image-width: 1200` failed the render, for an option that did nothing. Wiring them up was rejected: the same names already size the about-page image, so a top-level meaning would be ambiguous. - Remove both keys from the website document schema. Front matter accepts undeclared keys, so numeric and string values now render and are ignored. - Point the `image` option description at `open-graph` for declaring the preview image size. See #15040 and quarto-dev/quarto-web#2282 for the sizing rules and the existing "aren't used" note. Related to #12016
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
With
site-urlset,og:image:widthandog:image:heightdisappear for anopen-graphimage that Quarto cannot measure, even whenimage-widthandimage-heightare declared. #12016 reported it for a JPEG, which #15050 now measures. The remaining cases are remote images and formats Quarto does not read, such as SVG, GIF or WebP.Root cause
resolveImageMetadatainsrc/project/types/website/website-meta.tsalways replaced the declared size with the measured one, which isundefinedwhen the image can't be measured. Withoutsite-urlthis code is skipped, which is why removingsite-urlhides the problem.Fix
The measured size is still used when Quarto can read the file, so the tags describe the actual pixels. Otherwise the declared size is kept.
Keeping the declared size raises the question of which image it describes. A size declared in the site
open-graphoptions describes the site image, so it no longer applies when the page supplies its own image:image, a pageopen-graphimage, or a preview image found in the page content. That image only gets the dimensions declared in the pageopen-graphoptions, each one separately.image: falseand thewebsite.imagefallback keep the site image and its size.Compatibility
This changes the output of sites without
site-url. Before, the site-declared size was emitted on every page, including pages with their own image. A site that declared one size because all its page images share it now loses these tags on pages that set an image.The check is on whether the page declares an image, not on which file it is, so a page that repeats the site image also loses the site size.
To keep the tags, declare
image-widthandimage-heightunderopen-graphin the page front matter, or once in shared metadata such as_metadata.yml. Top-levelimage-widthandimage-heightin the page front matter are not read foropen-graph.Fixes #12016
Checklist
I have (if applicable):
AI-assisted PR
Note: autonomous AI agents submitting PRs without human oversight are not permitted — see the Code of Conduct.