tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

decode_exif_metadata.cc (5281B)


      1 // Copyright (c) the JPEG XL Project Authors. All rights reserved.
      2 //
      3 // Use of this source code is governed by a BSD-style
      4 // license that can be found in the LICENSE file.
      5 
      6 // This C++ example decodes a JPEG XL image in one shot (all input bytes
      7 // available at once). The example outputs the pixels and color information to a
      8 // floating point image and an ICC profile on disk.
      9 
     10 #include <jxl/decode.h>
     11 #include <jxl/decode_cxx.h>
     12 #include <limits.h>
     13 #include <stdint.h>
     14 #include <stdio.h>
     15 #include <string.h>
     16 
     17 #include <vector>
     18 
     19 bool DecodeJpegXlExif(const uint8_t* jxl, size_t size,
     20                      std::vector<uint8_t>* exif) {
     21  auto dec = JxlDecoderMake(nullptr);
     22 
     23  // We're only interested in the Exif boxes in this example, so don't
     24  // subscribe to events related to pixel data.
     25  if (JXL_DEC_SUCCESS != JxlDecoderSubscribeEvents(
     26                             dec.get(), JXL_DEC_BOX | JXL_DEC_BOX_COMPLETE)) {
     27    fprintf(stderr, "JxlDecoderSubscribeEvents failed\n");
     28    return false;
     29  }
     30  bool support_decompression = true;
     31  if (JXL_DEC_SUCCESS != JxlDecoderSetDecompressBoxes(dec.get(), JXL_TRUE)) {
     32    fprintf(stderr,
     33            "NOTE: decompressing brob boxes not supported with the currently "
     34            "used jxl library.\n");
     35    support_decompression = false;
     36  }
     37 
     38  JxlDecoderSetInput(dec.get(), jxl, size);
     39  JxlDecoderCloseInput(dec.get());
     40 
     41  const constexpr size_t kChunkSize = 65536;
     42  size_t output_pos = 0;
     43 
     44  for (;;) {
     45    JxlDecoderStatus status = JxlDecoderProcessInput(dec.get());
     46    if (status == JXL_DEC_ERROR) {
     47      fprintf(stderr, "Decoder error\n");
     48      return false;
     49    } else if (status == JXL_DEC_NEED_MORE_INPUT) {
     50      fprintf(stderr, "Error, already provided all input\n");
     51      return false;
     52    } else if (status == JXL_DEC_BOX) {
     53      if (!exif->empty()) {
     54        size_t remaining = JxlDecoderReleaseBoxBuffer(dec.get());
     55        exif->resize(exif->size() - remaining);
     56        // No need to wait for JXL_DEC_SUCCESS or decode other boxes.
     57        return true;
     58      }
     59      JxlBoxType type;
     60      status = JxlDecoderGetBoxType(dec.get(), type,
     61                                    TO_JXL_BOOL(support_decompression));
     62      if (JXL_DEC_SUCCESS != status) {
     63        fprintf(stderr, "Error, failed to get box type\n");
     64        return false;
     65      }
     66      if (!memcmp(type, "Exif", 4)) {
     67        exif->resize(kChunkSize);
     68        JxlDecoderSetBoxBuffer(dec.get(), exif->data(), exif->size());
     69      }
     70    } else if (status == JXL_DEC_BOX_NEED_MORE_OUTPUT) {
     71      size_t remaining = JxlDecoderReleaseBoxBuffer(dec.get());
     72      output_pos += kChunkSize - remaining;
     73      exif->resize(exif->size() + kChunkSize);
     74      JxlDecoderSetBoxBuffer(dec.get(), exif->data() + output_pos,
     75                             exif->size() - output_pos);
     76    } else if (status == JXL_DEC_BOX_COMPLETE) {
     77      if (!exif->empty()) {
     78        size_t remaining = JxlDecoderReleaseBoxBuffer(dec.get());
     79        exif->resize(exif->size() - remaining);
     80        return true;
     81      }
     82      return true;
     83    } else {
     84      fprintf(stderr, "Unknown decoder status\n");
     85      return false;
     86    }
     87  }
     88 }
     89 
     90 bool LoadFile(const char* filename, std::vector<uint8_t>* out) {
     91  FILE* file = fopen(filename, "rb");
     92  if (!file) {
     93    return false;
     94  }
     95 
     96  if (fseek(file, 0, SEEK_END) != 0) {
     97    fclose(file);
     98    return false;
     99  }
    100 
    101  long size = ftell(file);  // NOLINT
    102  // Avoid invalid file or directory.
    103  if (size >= LONG_MAX || size < 0) {
    104    fclose(file);
    105    return false;
    106  }
    107 
    108  if (fseek(file, 0, SEEK_SET) != 0) {
    109    fclose(file);
    110    return false;
    111  }
    112 
    113  out->resize(size);
    114  size_t readsize = fread(out->data(), 1, size, file);
    115  if (fclose(file) != 0) {
    116    return false;
    117  }
    118 
    119  return readsize == static_cast<size_t>(size);
    120 }
    121 
    122 bool WriteFile(const char* filename, const uint8_t* data, size_t size) {
    123  FILE* file = fopen(filename, "wb");
    124  if (!file) {
    125    fprintf(stderr, "Could not open %s for writing", filename);
    126    return false;
    127  }
    128  fwrite(data, 1, size, file);
    129  if (fclose(file) != 0) {
    130    return false;
    131  }
    132  return true;
    133 }
    134 
    135 int main(int argc, char* argv[]) {
    136  if (argc != 3) {
    137    fprintf(stderr,
    138            "Usage: %s <jxl> <exif>\n"
    139            "Where:\n"
    140            "  jxl = input JPEG XL image filename\n"
    141            "  exif = output exif filename\n"
    142            "Output files will be overwritten.\n",
    143            argv[0]);
    144    return 1;
    145  }
    146 
    147  const char* jxl_filename = argv[1];
    148  const char* exif_filename = argv[2];
    149 
    150  std::vector<uint8_t> jxl;
    151  if (!LoadFile(jxl_filename, &jxl)) {
    152    fprintf(stderr, "couldn't load %s\n", jxl_filename);
    153    return 1;
    154  }
    155 
    156  std::vector<uint8_t> exif;
    157  if (!DecodeJpegXlExif(jxl.data(), jxl.size(), &exif)) {
    158    fprintf(stderr, "Error while decoding the jxl file\n");
    159    return 1;
    160  }
    161  if (exif.empty()) {
    162    printf("No exif data present in this image\n");
    163  } else {
    164    // TODO(lode): the exif box data contains the 4-byte TIFF header at the
    165    // beginning, check whether this is desired to be part of the output, or
    166    // should be removed.
    167    if (!WriteFile(exif_filename, exif.data(), exif.size())) {
    168      fprintf(stderr, "Error while writing the exif file\n");
    169      return 1;
    170    }
    171    printf("Successfully wrote %s\n", exif_filename);
    172  }
    173  return 0;
    174 }