| // Copyright 2023 Google LLC |
| // SPDX-License-Identifier: BSD-2-Clause |
| |
| #include "printmetadata_command.h" |
| |
| #include <cassert> |
| #include <iomanip> |
| |
| #include "avif/avif_cxx.h" |
| |
| namespace avif { |
| |
| namespace { |
| template <typename T> |
| std::string FormatFraction(T numerator, uint32_t denominator) { |
| std::stringstream stream; |
| stream << (denominator != 0 ? (double)numerator / denominator : 0) |
| << " (as fraction: " << numerator << "/" << denominator << ")"; |
| return stream.str(); |
| } |
| |
| template <typename T> |
| std::string FormatFractions(const T numerator[3], |
| const uint32_t denominator[3]) { |
| std::stringstream stream; |
| const int w = 40; |
| stream << "R " << std::left << std::setw(w) |
| << FormatFraction(numerator[0], denominator[0]) << " G " << std::left |
| << std::setw(w) << FormatFraction(numerator[1], denominator[1]) |
| << " B " << std::left << std::setw(w) |
| << FormatFraction(numerator[2], denominator[2]); |
| return stream.str(); |
| } |
| } // namespace |
| |
| PrintMetadataCommand::PrintMetadataCommand() |
| : ProgramCommand("printmetadata", |
| "Prints the metadata of the gain map of an avif file") { |
| argparse_.add_argument(arg_input_filename_, "input_filename"); |
| } |
| |
| avifResult PrintMetadataCommand::Run() { |
| DecoderPtr decoder(avifDecoderCreate()); |
| if (decoder == NULL) { |
| return AVIF_RESULT_OUT_OF_MEMORY; |
| } |
| decoder->enableParsingGainMapMetadata = true; |
| |
| avifResult result = |
| avifDecoderSetIOFile(decoder.get(), arg_input_filename_.value().c_str()); |
| if (result != AVIF_RESULT_OK) { |
| std::cerr << "Cannot open file for read: " << arg_input_filename_ << "\n"; |
| return result; |
| } |
| result = avifDecoderParse(decoder.get()); |
| if (result != AVIF_RESULT_OK) { |
| std::cerr << "Failed to parse image: " << avifResultToString(result) << " (" |
| << decoder->diag.error << ")\n"; |
| return result; |
| } |
| if (!decoder->gainMapPresent) { |
| std::cerr << "Input image " << arg_input_filename_ |
| << " does not contain a gain map\n"; |
| return AVIF_RESULT_INVALID_ARGUMENT; |
| } |
| assert(decoder->image->gainMap); |
| |
| const avifGainMapMetadata& metadata = decoder->image->gainMap->metadata; |
| const int w = 20; |
| std::cout << " * " << std::left << std::setw(w) << "Base headroom: " |
| << FormatFraction(metadata.baseHdrHeadroomN, |
| metadata.baseHdrHeadroomD) |
| << "\n"; |
| std::cout << " * " << std::left << std::setw(w) << "Alternate headroom: " |
| << FormatFraction(metadata.alternateHdrHeadroomN, |
| metadata.alternateHdrHeadroomD) |
| << "\n"; |
| std::cout << " * " << std::left << std::setw(w) << "Gain Map Min: " |
| << FormatFractions(metadata.gainMapMinN, metadata.gainMapMinD) |
| << "\n"; |
| std::cout << " * " << std::left << std::setw(w) << "Gain Map Max: " |
| << FormatFractions(metadata.gainMapMaxN, metadata.gainMapMaxD) |
| << "\n"; |
| std::cout << " * " << std::left << std::setw(w) << "Base Offset: " |
| << FormatFractions(metadata.baseOffsetN, metadata.baseOffsetD) |
| << "\n"; |
| std::cout << " * " << std::left << std::setw(w) << "Alternate Offset: " |
| << FormatFractions(metadata.alternateOffsetN, |
| metadata.alternateOffsetD) |
| << "\n"; |
| std::cout << " * " << std::left << std::setw(w) << "Gain Map Gamma: " |
| << FormatFractions(metadata.gainMapGammaN, metadata.gainMapGammaD) |
| << "\n"; |
| std::cout << " * " << std::left << std::setw(w) << "Use Base Color Space: " |
| << (metadata.useBaseColorSpace ? "True" : "False") << "\n"; |
| |
| return AVIF_RESULT_OK; |
| } |
| |
| } // namespace avif |