Skip to content

Export JPG with AVM (WCS metadata)#4065

Open
bmorris3 wants to merge 7 commits into
spacetelescope:mainfrom
bmorris3:support-avm
Open

Export JPG with AVM (WCS metadata)#4065
bmorris3 wants to merge 7 commits into
spacetelescope:mainfrom
bmorris3:support-avm

Conversation

@bmorris3
Copy link
Copy Markdown
Contributor

@bmorris3 bmorris3 commented Mar 4, 2026

Description

The main goal of this PR is to allow users to export a screenshot of their image viewer and load that screenshot into aladin-lite or mast-aladin. In order to overlay the screenshot on the correct sky coordinates in aladin-lite, the screenshot must contain AVM.

AVM is a metadata standard for embedding WCS in common image formats, including PNG and JPG. The python module for embedding AVM from WCS is pyavm by @astrofrog, which is a new (and extremely minimal) dependency in this PR.

This PR adds a supported image viewer screenshot filetype ("jpg"). When selected, the Export plugin:

  1. exports a PNG as normal
  2. assembles WCS for the screenshot
  3. converts PNG to JPG using PIL, since PNG w/ AVM isn't yet supported by aladin-lite
  4. embeds the WCS into the final JPG, and cleans up temporary files

The result is a JPG file with AVM. You can check this by calling:

$ head imviz-0.jpg
����JFIF��^http://ns.adobe.com/xap/1.0/<?xpacket begin="" id="W5M0MpCehiHzreSzNTczkc9d"?> <x:xmpmeta xmlns:avm="http://www.communicatingastronomy.org/avm/1.0/" xmlns:photoshop="http://ns.adobe.com/photoshop/1.0/" xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns:x="adobe:ns:meta/"><rdf:RDF><rdf:Description><avm:MetadataVersion>1.1000000000000001</avm:MetadataVersion><photoshop:Source>jdaviz</photoshop:Source<avm:Spatial.CoordinateFrame>FK5</avm:Spatial.CoordinateFrame><avm:Spatial.Equinox>2000.0013661202186</avm:Spatial.Equinox><avm:Spatial.ReferenceValue><rdf:Seq><rdf:li>201.7042659999999898</rdf:li>...

See that madness? That's the WCS.

Now you can load the JPG with aladin-lite in your browser, or in an instance of mast-aladin. In either environment, right click* on the sky , select "Load a local file" > "FITS image"*, and select the imviz-0.jpg file (*see known issues below).

To try this out in a notebook with mast-aladin, run the following in one cell:

from mast_aladin import AppSidecar
import astropy.units as u
from astropy.coordinates import SkyCoord

# open mast-aladin and jdaviz
ma, viz = AppSidecar.open(anchor=['split-bottom', 'split-right'])
target = SkyCoord(ra=201.704266 * u.deg, dec=-47.44637979 * u.deg)
fov = 36 * u.arcsec

# set up the mast-aladin viewport
ma.target = target
ma.fov = fov
ma.survey = 'HST/color'

viz.load('mast:jwst/products/jw01478-o014_t003_nircam_clear-f115w_i2d.fits', format='Image')
viz.link_data('wcs')
viz.default_viewer.reset_limits()

# configure the colormap
plot_opts = viz.plugins['Plot Options']
plot_opts.image_colormap = 'viridis'
plot_opts.stretch_vmin = 5
plot_opts.stretch_vmax  = 1000
plot_opts.stretch_function = 'Arcsinh'

# set the jdaviz viewport to match mast-aladin
viz.default_viewer._obj.glue_viewer.aid.set_viewport(
    center=target,
    fov=fov
)

and in a second cell:

# export JPG with AVM
export = viz.plugins['Export']
export.viewer_format = 'jpg'
export.export(overwrite=True)

You will see this:

jdaviz-to-aladin-export-720.mov

Known issues

To do items before merge:

  • I haven't accounted for jdaviz users beginning in any orientation other than Default Orientation
  • should add logic to ensure that tmp files are removed if the export fails out early (prevent leaving tmp files)

Change log entry

  • Is a change log needed? If yes, is it added to CHANGES.rst? If you want to avoid merge conflicts,
    list the proposed change log here for review and add to CHANGES.rst before merge. If no, maintainer
    should add a no-changelog-entry-needed label.

Checklist for package maintainer(s)

This checklist is meant to remind the package maintainer(s) who will review this pull request of some common things to look for. This list is not exhaustive.

  • Are two approvals required? Branch protection rule does not check for the second approval. If a second approval is not necessary, please apply the trivial label.
  • Do the proposed changes actually accomplish desired goals? Also manually run the affected example notebooks, if necessary.
  • Do the proposed changes follow the STScI Style Guides?
  • Are tests added/updated as required? If so, do they follow the STScI Style Guides?
  • Are docs added/updated as required? If so, do they follow the STScI Style Guides?
  • If new remote data is added that uses MAST, is the URI added to the cache-download.yml workflow?
  • Did the CI pass? If not, are the failures related?
  • Is a milestone set? Set this to bugfix milestone if this is a bug fix and needs to be released ASAP; otherwise, set this to the next major release milestone. Bugfix milestone also needs an accompanying backport label.
  • After merge, any internal documentations need updating (e.g., JIRA, Innerspace)?

@github-actions github-actions Bot added the plugin Label for plugins common to multiple configurations label Mar 4, 2026
@bmorris3 bmorris3 marked this pull request as ready for review March 10, 2026 15:40
@bmorris3 bmorris3 added this to the 4.6 milestone Mar 10, 2026
@codecov
Copy link
Copy Markdown

codecov Bot commented Mar 10, 2026

Codecov Report

❌ Patch coverage is 33.33333% with 26 lines in your changes missing coverage. Please review.
✅ Project coverage is 84.51%. Comparing base (20e3eaa) to head (44d8dbf).

Files with missing lines Patch % Lines
jdaviz/configs/default/plugins/export/avm.py 24.00% 19 Missing ⚠️
jdaviz/configs/default/plugins/export/export.py 41.66% 7 Missing ⚠️

❌ Your patch check has failed because the patch coverage (33.33%) is below the target coverage (90.00%). You can increase the patch coverage or adjust the target coverage.

Additional details and impacted files
@@            Coverage Diff             @@
##             main    #4065      +/-   ##
==========================================
- Coverage   84.60%   84.51%   -0.10%     
==========================================
  Files         202      203       +1     
  Lines       29402    29436      +34     
==========================================
+ Hits        24876    24878       +2     
- Misses       4526     4558      +32     

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

@astrofrog
Copy link
Copy Markdown
Collaborator

@bmorris3 - just FYI I released pyavm 0.9.9 today which fixes a few bugs. I don't suspect these were affecting you here, but let me know if you have any issues with this new version.

@bmorris3
Copy link
Copy Markdown
Contributor Author

Thank you @astrofrog!

Comment thread jdaviz/configs/default/plugins/export/export.py Outdated
output file already exists. Otherwise, a message will be sent
to application snackbar instead.

embed_avm : bool
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

would there be any harm to having this on by default (or not even have the option to turn it off)?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think there's any harm. I think we should preserve the option to turn it off, just in case there's ever an upstream bug.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I guess the downside is that it might be confusing for non-supported filetypes if the user passes this as true (or leaves it at the default) and we don't have checking that raises an error 🤔


try:
# export PNG
tmp_filename = Path(str(Path(filename)).replace('.jpg', '.png'))
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

can this be done by writing to a buffer instead of a temporary file to disk?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@astrofrog
Copy link
Copy Markdown
Collaborator

Is there any reason not to allow PNG export already as other tools may be able to use them?

Co-authored-by: Kyle Conroy <kyleconroy@gmail.com>
Copy link
Copy Markdown
Collaborator

@pcuste1 pcuste1 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pulled this PR down locally and it is working as advertised. As noted, it hasn't been designed with rotation in mind, and it handles at bit weird once the imviz viewer is rotated. This is likely in part due to the missing alpha channel and the change in FOV caused by rotation. We'll want to look further into this in a future PR. I'm also curious how it will handle projection once we introduce the feature to update that into jdaviz. Preliminary tests also show that WCS near the poles are handled properly as well

@rosteen rosteen modified the milestones: 4.6, 5.1 Apr 15, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

plugin Label for plugins common to multiple configurations

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants