Skip to content

Commit

Permalink
Add support to encode and decode mapping tables (#302)
Browse files Browse the repository at this point in the history
* Add support to write mapping tables to the JPEG byte stream.
* Add API method to set the table ID for a component
* Add method to create JPEG-LS file with mapping tables only.
* Add support to read mapping tables
* Parse table-ids from the scan segment
* Extend API of charls_decoder_get_mapping_table_index to return -1 if index is not found
* Add support to read mapping table continuation segments
* Document new API methods
* Add sample image from appendix H.4.5 "Example of a palletised image" / Figure H.10 to unit test
* Update the get_mapping_table API to include size of the buffer
  • Loading branch information
vbaderks authored Jul 23, 2024
1 parent f2ff444 commit eaba4b0
Show file tree
Hide file tree
Showing 34 changed files with 1,993 additions and 186 deletions.
8 changes: 1 addition & 7 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,16 +1,10 @@
# GIT ignore file for CharLS

obj/
bin/
Win32/
x64/
.vscode/
.vs/
.idea
build*/
[Dd]ebug/
[Rr]elease/
[Cc]hecked/
cmake-build-debug/
TestResults/
vcpkg_installed/
*.opensdf
Expand Down
16 changes: 12 additions & 4 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,22 @@

All notable changes to this project are documented in this file.

The format is based on [Keep a Changelog](http://keepachangelog.com/) and this project adheres to [Semantic Versioning](http://semver.org/).
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/) and this project adheres to [Semantic Versioning](http://semver.org/).

## [3.0.0] -
## [3.0.0] - UNRELEASED

### Added

- Support to encode and decode mapping tables.

### Changed

- Updated the source code to C++17. This is a breaking change, high version is updated to 3.
- encoding_options::include_pc_parameters_jai is not enabled by default anymore. This is a breaking change.
- BREAKING: Updated the minimal required C++ language version to C++17.
- BREAKING: encoding_options::include_pc_parameters_jai is not enabled by default anymore.

### Removed

- BREAKING: Legacy 1.x API methods have been removed.

## [2.4.2] - 2023-5-16

Expand Down
2 changes: 1 addition & 1 deletion CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
# Copyright (c) Team CharLS.
# SPDX-License-Identifier: BSD-3-Clause

cmake_minimum_required(VERSION 3.13...3.26)
cmake_minimum_required(VERSION 3.13...3.30)

# Extract the version info from version.h
file(READ "include/charls/version.h" version)
Expand Down
2 changes: 2 additions & 0 deletions CharLS.sln.DotSettings
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,8 @@
<s:Boolean x:Key="/Default/UserDictionary/Words/=NOLINTNEXTLINE/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=opto/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=oversized/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=palettised/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=palletised/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=ptype/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=qbpp/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=RGBRGBRGB/@EntryIndexedValue">True</s:Boolean>
Expand Down
1 change: 0 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,6 @@ The following JPEG-LS options are not supported by the CharLS implementation. Mo
While technical possible all known JPEG-LS codecs put multi-component (color) images in a single scan
or in multiple scans, but not use a mix of these in one file.
* No support to encode\decode images with the height defined after the first scan (DNL marker).
* No support for JPEG-LS mapping tables (palette).
* No support for point transform.
Point transform is a lossly encoding mechanism and not used in lossless scenarios.

Expand Down
2 changes: 1 addition & 1 deletion azure-pipelines.yml
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ jobs:
platform: '$(buildPlatform)'
configuration: '$(buildConfiguration)'
maximumCpuCount: true
msbuildArgs: -p:CHARLS_PROFILE=true -p:CHARLS_ALL_WARNINGS=true -p:VCToolsVersion=14.38.33130
msbuildArgs: -p:CHARLS_PROFILE=true -p:CHARLS_ALL_WARNINGS=true

- task: VSTest@2
inputs:
Expand Down
3 changes: 3 additions & 0 deletions cpp.hint
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@
#define CHARLS_NO_INLINE
#define FORCE_INLINE
#define MSVC_WARNING_SUPPRESS_NEXT_LINE(x)
#define MSVC_WARNING_SUPPRESS(x)
#define MSVC_WARNING_UNSUPPRESS
#define CHARLS_IN
#define CHARLS_IN_OPT
#define CHARLS_IN_Z
Expand All @@ -27,6 +29,7 @@
#define CHARLS_ATTRIBUTE(a)
#define CHARLS_ATTRIBUTE_ACCESS(a)
#define CHARLS_C_VOID
#define CHARLS_EXPORT
#define CHARLS_CHECK_RETURN
#define CHARLS_RET_MAY_BE_NULL
#define USE_DECL_ANNOTATIONS
Expand Down
1 change: 1 addition & 0 deletions default.ruleset
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
<Rule Id="C26482" Action="None" />
<Rule Id="C26485" Action="None" />
<Rule Id="C26490" Action="None" />
<Rule Id="C26493" Action="None" />
<Rule Id="C26494" Action="None" />
</Rules>
</RuleSet>
3 changes: 3 additions & 0 deletions default.ruleset.md
Original file line number Diff line number Diff line change
Expand Up @@ -24,5 +24,8 @@ C26482: Only index into arrays using constant expressions.
C26490: Don't use reinterpret_cast
-> Rationale: required to cast unsigned char* to char*.

C26493: Don't use C-style casts (type.4).
-> Rationale: False positives in Visual Studio 2022 17.11.0 Preview 3.0

C26494: Variable 'x' is uninitialized. Always initialize an object
-> Rationale: many false warnings, other analyzers are better.
179 changes: 176 additions & 3 deletions include/charls/charls_jpegls_decoder.h
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
#ifndef CHARLS_BUILD_AS_CPP_MODULE
#include <functional>
#include <memory>
#include <optional>
#include <utility>
#endif

Expand Down Expand Up @@ -219,6 +220,79 @@ charls_jpegls_decoder_at_application_data(CHARLS_IN charls_jpegls_decoder* decod
charls_at_application_data_handler handler, void* user_context) CHARLS_NOEXCEPT
CHARLS_ATTRIBUTE((nonnull(1)));

/// <summary>
/// Returns the mapping table ID referenced by the component or 0 when no mapping table is used.
/// </summary>
/// <remarks>
/// Function should be called after processing the complete JPEG-LS stream.
/// </remarks>
/// <param name="decoder">Reference to the decoder instance.</param>
/// <param name="component_index">Index of the component.</param>
/// <param name="table_id">Output argument, will hold the mapping table ID when the function returns or 0.</param>
/// <returns>The result of the operation: success or a failure code.</returns>
CHARLS_CHECK_RETURN CHARLS_API_IMPORT_EXPORT charls_jpegls_errc CHARLS_API_CALLING_CONVENTION
charls_decoder_get_mapping_table_id(CHARLS_IN const charls_jpegls_decoder* decoder, int32_t component_index,
CHARLS_OUT int32_t* table_id) CHARLS_NOEXCEPT CHARLS_ATTRIBUTE((nonnull));

/// <summary>
/// Converts the mapping table ID to a mapping table index.
/// When the requested table is not present in the JPEG-LS stream the value -1 will be returned.
/// </summary>
/// <remarks>
/// Function should be called after processing the complete JPEG-LS stream.
/// </remarks>
/// <param name="decoder">Reference to the decoder instance.</param>
/// <param name="table_id">Mapping table ID to lookup.</param>
/// <param name="index">Output argument, will hold the mapping table index or -1 when the function returns.</param>
/// <returns>The result of the operation: success or a failure code.</returns>
CHARLS_CHECK_RETURN CHARLS_API_IMPORT_EXPORT charls_jpegls_errc CHARLS_API_CALLING_CONVENTION
charls_decoder_get_mapping_table_index(CHARLS_IN const charls_jpegls_decoder* decoder, int32_t table_id,
CHARLS_OUT int32_t* index) CHARLS_NOEXCEPT CHARLS_ATTRIBUTE((nonnull));

/// <summary>
/// Returns the count of mapping tables present in the JPEG-LS stream.
/// </summary>
/// <remarks>
/// Function should be called after processing the complete JPEG-LS stream.
/// </remarks>
/// <param name="decoder">Reference to the decoder instance.</param>
/// <param name="count">Output argument, will hold the mapping table count when the function returns.</param>
/// <returns>The result of the operation: success or a failure code.</returns>
CHARLS_CHECK_RETURN CHARLS_API_IMPORT_EXPORT charls_jpegls_errc CHARLS_API_CALLING_CONVENTION
charls_decoder_get_mapping_table_count(CHARLS_IN const charls_jpegls_decoder* decoder,
CHARLS_OUT int32_t* count) CHARLS_NOEXCEPT CHARLS_ATTRIBUTE((nonnull));

/// <summary>
/// Returns information about a mapping table.
/// </summary>
/// <remarks>
/// Function should be called after processing the complete JPEG-LS stream.
/// </remarks>
/// <param name="decoder">Reference to the decoder instance.</param>
/// <param name="index">Index of the requested mapping table.</param>
/// <param name="table_info">Output argument, will hold the mapping table information when the function returns.</param>
/// <returns>The result of the operation: success or a failure code.</returns>
CHARLS_CHECK_RETURN CHARLS_API_IMPORT_EXPORT charls_jpegls_errc CHARLS_API_CALLING_CONVENTION
charls_decoder_get_mapping_table_info(CHARLS_IN const charls_jpegls_decoder* decoder, int32_t index,
CHARLS_OUT charls_table_info* table_info) CHARLS_NOEXCEPT CHARLS_ATTRIBUTE((nonnull));

/// <summary>
/// Returns a mapping table.
/// </summary>
/// <remarks>
/// Function should be called after processing the complete JPEG-LS stream.
/// </remarks>
/// <param name="decoder">Reference to the decoder instance.</param>
/// <param name="index">Index of the requested mapping table.</param>
/// <param name="table_data">Output argument, will hold the data of the mapping table when the function returns.</param>
/// <param name="table_size_bytes">Length of the mapping table buffer in bytes.</param>
/// <returns>The result of the operation: success or a failure code.</returns>
CHARLS_ATTRIBUTE_ACCESS((access(write_only, 3, 4)))
CHARLS_CHECK_RETURN CHARLS_API_IMPORT_EXPORT charls_jpegls_errc CHARLS_API_CALLING_CONVENTION
charls_decoder_get_mapping_table(CHARLS_IN const charls_jpegls_decoder* decoder, int32_t index,
CHARLS_OUT_WRITES_BYTES(table_size_bytes) void* table_data,
size_t table_size_bytes) CHARLS_NOEXCEPT CHARLS_ATTRIBUTE((nonnull));

#ifdef __cplusplus

} // extern "C"
Expand Down Expand Up @@ -524,9 +598,7 @@ class jpegls_decoder final
/// Will decode the JPEG-LS byte stream set with source into the destination buffer.
/// </summary>
/// <param name="destination_buffer">Byte array that holds the encoded bytes when the function returns.</param>
/// <param name="destination_size_bytes">
/// Length of the array in bytes. If the array is too small the function will return an error.
/// </param>
/// <param name="destination_size_bytes">Length of the destination buffer in bytes.</param>
/// <param name="stride">Number of bytes to the next line in the buffer, when zero, decoder will compute it.</param>
/// <exception cref="charls::jpegls_error">An error occurred during the operation.</exception>
CHARLS_ATTRIBUTE_ACCESS((access(write_only, 2, 3)))
Expand Down Expand Up @@ -604,6 +676,107 @@ class jpegls_decoder final
return *this;
}

/// <summary>
/// Returns the mapping table ID referenced by the component or 0 when no mapping table is used.
/// </summary>
/// <remarks>
/// Function should be called after processing the complete JPEG-LS stream.
/// </remarks>
/// <param name="component_index">Index of the component.</param>
/// <returns>The mapping table ID or 0 when no mapping table is referenced by the component.</returns>
/// <exception cref="charls::jpegls_error">An error occurred during the operation.</exception>
[[nodiscard]]
int32_t mapping_table_id(const int32_t component_index) const
{
int32_t table_id;
check_jpegls_errc(charls_decoder_get_mapping_table_id(decoder_.get(), component_index, &table_id));
return table_id;
}

/// <summary>
/// Converts the mapping table ID to a mapping table index.
/// </summary>
/// <remarks>
/// Function should be called after processing the complete JPEG-LS stream.
/// </remarks>
/// <param name="table_id">Mapping table ID to lookup.</param>
/// <returns>
/// The index of the mapping table or an empty optional when the table is not present in the JPEG-LS stream.
/// </returns>
/// <exception cref="charls::jpegls_error">An error occurred during the operation.</exception>
[[nodiscard]]
std::optional<int32_t> mapping_table_index(const int32_t table_id) const
{
int32_t index;
check_jpegls_errc(charls_decoder_get_mapping_table_index(decoder_.get(), table_id, &index));
return index == mapping_table_missing ? std::optional<int32_t>{} : index;
}

/// <summary>
/// Returns the count of mapping tables present in the JPEG-LS stream.
/// </summary>
/// <remarks>
/// Function should be called after processing the complete JPEG-LS stream.
/// </remarks>
/// <returns>The number of mapping tables present in the JPEG-LS stream.</returns>
/// <exception cref="charls::jpegls_error">An error occurred during the operation.</exception>
[[nodiscard]]
int32_t mapping_table_count() const
{
int32_t count;
check_jpegls_errc(charls_decoder_get_mapping_table_count(decoder_.get(), &count));
return count;
}

/// <summary>
/// Returns information about a mapping table.
/// </summary>
/// <remarks>
/// Function should be called after processing the complete JPEG-LS stream.
/// </remarks>
/// <param name="index">Index of the requested mapping table.</param>
/// <returns>Mapping table information</returns>
/// <exception cref="charls::jpegls_error">An error occurred during the operation.</exception>
[[nodiscard]]
table_info mapping_table_info(const int32_t index) const
{
table_info info;
check_jpegls_errc(charls_decoder_get_mapping_table_info(decoder_.get(), index, &info));
return info;
}

/// <summary>
/// Returns a mapping table.
/// </summary>
/// <remarks>
/// Function should be called after processing the complete JPEG-LS stream.
/// </remarks>
/// <param name="index">Index of the requested mapping table.</param>
/// <param name="table_data">Output argument, will hold the data of mapping table when the function returns.</param>
/// <param name="table_size_bytes">Length of the table buffer in bytes.</param>
/// <exception cref="charls::jpegls_error">An error occurred during the operation.</exception>
CHARLS_ATTRIBUTE_ACCESS((access(write_only, 3, 4)))
void mapping_table(const int32_t index, CHARLS_OUT_WRITES_BYTES(table_size_bytes) void* table_data,
const size_t table_size_bytes) const
{
check_jpegls_errc(charls_decoder_get_mapping_table(decoder_.get(), index, table_data, table_size_bytes));
}

/// <summary>
/// Returns a mapping table.
/// </summary>
/// <remarks>
/// Function should be called after processing the complete JPEG-LS stream.
/// </remarks>
/// <param name="index">Index of the requested mapping table.</param>
/// <param name="table_data">Output argument, will hold data of the mapping table when the function returns.</param>
/// <exception cref="charls::jpegls_error">An error occurred during the operation.</exception>
template<typename Container, typename ContainerValueType = typename Container::value_type>
void mapping_table(const int32_t index, Container& table_data) const
{
mapping_table(index, table_data.data(), table_data.size() * sizeof(ContainerValueType));
}

private:
[[nodiscard]]
static charls_jpegls_decoder* create_decoder()
Expand Down
Loading

0 comments on commit eaba4b0

Please sign in to comment.