Skip to content

feat(oiiotool): Add thumbnail get/set commands and fix TGA thumbnail I/O - #5236

Merged
lgritz merged 11 commits into
AcademySoftwareFoundation:mainfrom
jinhgkim:oiiotool-thumbnail
Jul 28, 2026
Merged

feat(oiiotool): Add thumbnail get/set commands and fix TGA thumbnail I/O#5236
lgritz merged 11 commits into
AcademySoftwareFoundation:mainfrom
jinhgkim:oiiotool-thumbnail

Conversation

@jinhgkim

@jinhgkim jinhgkim commented Jun 15, 2026

Copy link
Copy Markdown
Contributor

Description

Adds oiiotool commands to extract and attach embedded thumbnails, and fixes TGA postage-stamp read/write bugs they exposed.

Fixes #4889.

Note that thumbnail support is uneven across formats: get_thumbnail is implemented for PSD, camera RAW, and TGA, but set_thumbnail only for TGA. So you can read thumbnails from several formats, yet TGA is the only format that writes an embedded thumbnail today. e.g., input.exr ... --thumbnail-set -o out.exr silently produces an EXR with no embedded thumbnail.

  • Features:

    • oiiotool: add --thumbnail-get
    • oiiotool: add -i:get_thumbnail=1
    • oiiotool: add --thumbnail-set
  • Fixes:

    • targa thumbnail write: encode thumbnail like the main image (bottom-up, deassociated alpha, BGR(A))
    • targa thumbnail read: apply associateAlpha()

Assisted-by: Claude Code / opus-4.8

Tests

New tests in oiiotool-thumbnail-get, oiiotool-thumbnail-set, imagebuf_test

Checklist:

  • I have read the guidelines on contributions and code review procedures.
  • I have read the Policy on AI Coding Assistants
    and if I used AI coding assistants, I have an Assisted-by: TOOL / MODEL
    line in the pull request description above.
  • I have updated the documentation if my PR adds features or changes
    behavior.
  • I am sure that this PR's changes are tested in the testsuite.
  • I have run and passed the testsuite in CI before submitting the
    PR, by pushing the changes to my fork and seeing that the automated CI
    passed there. (Exceptions: If most tests pass and you can't figure out why
    the remaining ones fail, it's ok to submit the PR and ask for help. Or if
    any failures seem entirely unrelated to your change; sometimes things break
    on the GitHub runners.)
  • My code follows the prevailing code style of this project and I
    fixed any problems reported by the clang-format CI test.
  • If I added or modified a public C++ API call, I have also amended the
    corresponding Python bindings. If altering ImageBufAlgo functions, I also
    exposed the new functionality as oiiotool options.

@linux-foundation-easycla

linux-foundation-easycla Bot commented Jun 15, 2026

Copy link
Copy Markdown

CLA Signed
The committers listed above are authorized under a signed CLA.

@jinhgkim
jinhgkim force-pushed the oiiotool-thumbnail branch 2 times, most recently from 2b002d9 to c589b11 Compare June 15, 2026 05:44
@jinhgkim

jinhgkim commented Jun 15, 2026

Copy link
Copy Markdown
Contributor Author

During the CI run, a TGA thumbnail test failed because I added associateAlpha() logic in this branch. My reasoning is that if we apply associateAlpha() in TGAInput::readimg(), we should apply the same operation when reading thumbnails.

Let me know what you think.

Also, fyi, I have broken down the commits into logical steps with some details in the commit message.

@lgritz lgritz left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

This more or less LGTM. I didn't click approve only because I want to give you the chance to respond to some of the comments I left, none of which are strictly required, but maybe you'll particularly want to do some of those things.

Comment thread src/doc/oiiotool.rst Outdated
Comment on lines +2365 to +2367
If 0, an empty (0x0) image is pushed in its place instead, so a batch
script can continue; guard any subsequent output (see the example
below), since writing the empty image is itself an error.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Two things to consider here.

  1. I'm not sure how resilient anything downstream will be to a literal 0x0 image.
  2. Does it make more sense for a "handled failure" to be either (a) just leave the original full-size image on the stack, or (b) perform the equivalent of a --resize or --resample to a reasonable thumbnail-like resolution?

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.

Addressed in c056367

Comment thread src/oiiotool/oiiotool.cpp Outdated
Comment on lines +7510 to +7515
ap.arg("--get-thumbnail")
.help("Extract an embedded thumbnail (options: fail=, index=)")
.OTACTION(action_get_thumbnail);
ap.arg("--set-thumbnail")
.help("Attach the top image as the thumbnail of the image below it")
.OTACTION(action_set_thumbnail);

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

I'm not sure I feel strongly about this, but want to throw it out there in case it resonates with you. Would you prefer "--thumbnail-get" and "--thumbnail-set" for the sake of ensuring that they are always next to each other in an alphabetical listing of commands?

We purposely picked --mulc so that it would be next to --mul in alphabetical listings for similar reason.

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.

That makes sense to me. Addressed in 470541c.

Comment thread src/targa.imageio/targainput.cpp
@lgritz

lgritz commented Jun 15, 2026

Copy link
Copy Markdown
Collaborator

Just another suggestion I thought of while reviewing this, so I'll mention it here. Though you need not add it, maybe it's an item for a follow-up, or just to put on the list of extensions to consider for some day (maybe only after index= works?).

Do you think it would be useful to have a :requested=WxH hint that, if more than one thumbnail were present, would pick the one closest to what you ask for? You could even imagine a few variants that extend it, like :requested=<WxH means the largest thumbnail that fits in WxH, :requested=>WxH means "the smallest thumbnail at least that size" and :requested=WxH! means "I really need that size exactly, pick the best but also resize/fit if you need to."

jinhgkim added 11 commits July 26, 2026 12:22
Assisted-by: Claude Code / opus-4.8
Signed-off-by: Jinnie Kim <jinhgkim@gmail.com>
Assisted-by: Claude Code / opus-4.8
Signed-off-by: Jinnie Kim <jinhgkim@gmail.com>
Signed-off-by: Jinnie Kim <jinhgkim@gmail.com>
Assisted-by: Claude Code / opus-4.8
Signed-off-by: Jinnie Kim <jinhgkim@gmail.com>
Encode the embedded thumbnail the same way as the main image: bottom-up
scanlines, deassociated alpha, and BGR(A) channel order. The original
implementation rather dumped the raw in-memory buffer, which left the
thumbnail flipped, R/B-swapped, and premultiplied.

Also clamp an oversized thumbnail to 255 rather than 256: each postage-stamp
dimension is a single byte, so 256 wrapped to 0 and the thumbnail was
silently dropped on read.

Assisted-by: Claude Code / opus-4.8
Signed-off-by: Jinnie Kim <jinhgkim@gmail.com>
TGA stores unassociated alpha, but OIIO keeps it associated in memory.
`readimg()` converts on read; `get_thumbnail()` did not, so RGBA thumbnails came
back too bright. Apply the same `associateAlpha()` conversion to the thumbnail.

get_thumbnail() is moved below associateAlpha() so it can call it without a
forward declaration.

Assisted-by: Claude Code / opus-4.8
Signed-off-by: Jinnie Kim <jinhgkim@gmail.com>
Assisted-by: Claude Code / opus-4.8
Signed-off-by: Jinnie Kim <jinhgkim@gmail.com>
Signed-off-by: Jinnie Kim <jinhgkim@gmail.com>
…set`

Signed-off-by: Jinnie Kim <jinhgkim@gmail.com>
Assisted-by: Claude Code / opus-4.8
Signed-off-by: Jinnie Kim <jinhgkim@gmail.com>
get_thumbnail() now associates alpha to match readimg(), so the old
references no longer match. Only CTC32 and UTC32 change and the rest
without alpha remain unaffected.

Signed-off-by: Jinnie Kim <jinhgkim@gmail.com>
@jinhgkim
jinhgkim force-pushed the oiiotool-thumbnail branch from c589b11 to dfd54e6 Compare July 27, 2026 06:59
@jinhgkim

jinhgkim commented Jul 27, 2026

Copy link
Copy Markdown
Contributor Author

@lgritz, sorry for the delayed response. Hopefully this is still fresh enough that you don't need to re-review from scratch. (I've pushed three new commits)

Just another suggestion I thought of while reviewing this, so I'll mention it here. Though you need not add it, maybe it's an item for a follow-up, or just to put on the list of extensions to consider for some day (maybe only after index= works?).

Do you think it would be useful to have a :requested=WxH hint that, if more than one thumbnail were present, would pick the one closest to what you ask for? You could even imagine a few variants that extend it, like :requested=<WxH means the largest thumbnail that fits in WxH, :requested=>WxH means "the smallest thumbnail at least that size" and :requested=WxH! means "I really need that size exactly, pick the best but also resize/fit if you need to."

Yes, that would be useful. It might also be worth allowing a single number, :requested=200 meaning "the thumbnail whose shorter/longer side is closest to 200."

@lgritz

lgritz commented Jul 27, 2026

Copy link
Copy Markdown
Collaborator

@jinhgkim make sure you see #5334 and weigh in on any issues there.

Comment thread src/doc/oiiotool.rst
Comment thread src/doc/oiiotool.rst
@lgritz

lgritz commented Jul 28, 2026

Copy link
Copy Markdown
Collaborator

@jinhgkim I think this is about ready to go. I just had one outstanding comment, which is that if the :index= modifier is not currently functional, that should be noted in the docs.

@lgritz lgritz left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

LGTM, thanks for this PR. And timely, Anton can build on this for his work with raw.

@lgritz
lgritz merged commit 7d70620 into AcademySoftwareFoundation:main Jul 28, 2026
62 checks passed
lgritz pushed a commit to lgritz/OpenImageIO that referenced this pull request Jul 30, 2026
…I/O (AcademySoftwareFoundation#5236)

Adds `oiiotool` commands to extract and attach embedded thumbnails, and
fixes TGA postage-stamp read/write bugs they exposed. 

Fixes AcademySoftwareFoundation#4889.

Note that thumbnail support is uneven across formats: `get_thumbnail` is
implemented for PSD, camera RAW, and TGA, but `set_thumbnail` only for
TGA. So you can read thumbnails from several formats, yet TGA is the
only format that writes an embedded thumbnail today. e.g., `input.exr
... --thumbnail-set -o out.exr` silently produces an EXR with no
embedded thumbnail.

- Features:
  - `oiiotool`: add `--thumbnail-get`
  - `oiiotool`: add `-i:get_thumbnail=1`
  - `oiiotool`: add `--thumbnail-set`
  
- Fixes:
  - targa thumbnail `write`: encode thumbnail like the main image
(bottom-up, deassociated alpha, BGR(A))
  - targa thumbnail `read`: apply `associateAlpha()`
 
New tests in `oiiotool-thumbnail-get`, `oiiotool-thumbnail-set`,
`imagebuf_test`

Assisted-by: Claude Code / opus-4.8

---------

Signed-off-by: Jinnie Kim <jinhgkim@gmail.com>
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.

[FEATURE REQUEST] oiiotool thumbnail extraction

2 participants