Repository navigation
Add ICC profile support (get/set/embed) via TurboJPEG 3.1+ API - #114
Conversation
…c_profile, encode icc_profile param, tests Co-authored-by: lilohuang <8341304+lilohuang@users.noreply.github.com>
|
@copilot Since PyTurboJPEG already includes a TurboJPEG 3.0 API check, there is no need to re-verify version availability when getting or setting the ICC profile. |
… set_icc_profile Co-authored-by: lilohuang <8341304+lilohuang@users.noreply.github.com>
Done in ad0b62a. Removed the |
|
@copilot The ctypes wrapper functions do not use the _fn suffix; please follow the existing naming convention. |
…aming convention Co-authored-by: lilohuang <8341304+lilohuang@users.noreply.github.com>
|
@copilot Since ICC support requires TurboJPEG 3.1+, use the existing try...except pattern from self.__decompressToYUVPlanes16 to handle potential AttributeError on older 3.x versions. |
…ementedError guards Co-authored-by: lilohuang <8341304+lilohuang@users.noreply.github.com>
Done in 63d8eb0. Both |
@copilot Update the Python unit tests accordingly |
…plementedError) Co-authored-by: lilohuang <8341304+lilohuang@users.noreply.github.com>
Done in 0183ebe. Added an |
Extends
TurboJPEGto support ICC profile extraction and embedding usingtj3GetICCProfile/tj3SetICCProfilefrom the TurboJPEG 3.1+ API.Changes
turbojpeg.pyTJPARAM_SAVEMARKERS = 25— enables APP2 marker retention during header parsing__get_icc_profileand__set_icc_profileregistered using the existingtry/except AttributeErrorpattern (set toNoneon older 3.x builds that lack these symbols), following the same convention as other TurboJPEG 3.1+ functions such as__decompressToYUVPlanes16get_icc_profile(jpeg_buf): parses JPEG header with APP2 markers enabled, extracts and returns the ICC profile asbytes, orNoneif absent; raisesNotImplementedErrorwhen the underlying symbol is unavailable (libjpeg-turbo < 3.1)set_icc_profile(handle, icc_buf): low-level helper to attach raw ICC bytes to an active compressor handle; raisesNotImplementedErrorwhen unavailableencode(): added optionalicc_profile=Noneparameter; when provided, callsset_icc_profileafter image array validationtests/test_turbojpeg.pyMINIMAL_SRGB_ICC— programmatically constructed 132-byte structurally valid ICC profile (no external files needed)TestICCProfilewith three self-contained tests: embed+extract, no-profile returnsNone, and full roundtrip fidelity checkTestICCProfiletests are automatically skipped when the loaded libjpeg-turbo does not supporttj3GetICCProfile(i.e. libjpeg-turbo < 3.1), via anautousefixture that raisespytest.skiponNotImplementedErrorUsage
Original prompt
Summary
Extend the
TurboJPEGclass inturbojpeg.pyto support ICC Profile features introduced in TurboJPEG 3.0, and add corresponding unit tests intests/test_turbojpeg.py.Background & Context
The existing codebase (
turbojpeg.py) already wraps the TurboJPEG 3.x API usingctypes. Key patterns already established:self.__init(TJINIT_DECOMPRESS)orself.__init(TJINIT_COMPRESS), then destroyed withself.__destroy(handle)in afinallyblock.self.__set(handle, TJPARAM_*, value).self.__decompress_header(handle, src_addr, size)thenself.__get(handle, TJPARAM_*).self.__copy_from_buffer(ptr, size)and freed viaself.__free(ptr).self.__report_error(handle).The TJPARAM constants are defined around line 170–195 of
turbojpeg.py. The highest currently defined isTJPARAM_MAXMEMORY = 24.Changes Required
1.
turbojpeg.py— Add new constantIn the TJPARAM constants block (after
TJPARAM_MAXMEMORY = 24), add:This constant maps to
TJPARAM_SAVEMARKERSfrom the TurboJPEG 3.x header. Setting it to2(APP2) saves APP2 markers (used for ICC profiles) when parsing the header.2.
turbojpeg.py— Wire uptj3GetICCProfileandtj3SetICCProfilein__init__In the
TurboJPEG.__init__method, after the existing ctypes bindings (e.g., afterself.__get_error_codeor near the end of the binding block), add bindings for two new TurboJPEG 3.x functions:Handle the case where these functions might not be present (for forward-compatibility with older 3.x builds) by wrapping with
try/except AttributeErrorand setting them toNone, similar to howself.__decompressToYUVPlanes16 = Noneis handled when the function is absent.3.
turbojpeg.py— Addget_icc_profile(jpeg_buf)public methodAdd this method to the
TurboJPEGclass (a good location is near/afterdecode_header):4.
turbojpeg.py— Addset_icc_profile(handle, icc_buf)helper +encode_with_icc_profile()pu...This pull request was created from Copilot chat.
💡 You can make Copilot smarter by setting up custom instructions, customizing its development environment and configuring Model Context Protocol (MCP) servers. Learn more Copilot coding agent tips in the docs.