libjxl

FORK: libjxl patches used on blog
git clone https://git.neptards.moe/blog/libjxl.git
Log | Files | Refs | Submodules | README | LICENSE

decode_exif_metadata.cc (5212B)


      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(dec.get(), JXL_DEC_BOX)) {
     26     fprintf(stderr, "JxlDecoderSubscribeEvents failed\n");
     27     return false;
     28   }
     29   bool support_decompression = true;
     30   if (JXL_DEC_SUCCESS != JxlDecoderSetDecompressBoxes(dec.get(), JXL_TRUE)) {
     31     fprintf(stderr,
     32             "NOTE: decompressing brob boxes not supported with the currently "
     33             "used jxl library.\n");
     34     support_decompression = false;
     35   }
     36 
     37   JxlDecoderSetInput(dec.get(), jxl, size);
     38   JxlDecoderCloseInput(dec.get());
     39 
     40   const constexpr size_t kChunkSize = 65536;
     41   size_t output_pos = 0;
     42 
     43   for (;;) {
     44     JxlDecoderStatus status = JxlDecoderProcessInput(dec.get());
     45     if (status == JXL_DEC_ERROR) {
     46       fprintf(stderr, "Decoder error\n");
     47       return false;
     48     } else if (status == JXL_DEC_NEED_MORE_INPUT) {
     49       fprintf(stderr, "Error, already provided all input\n");
     50       return false;
     51     } else if (status == JXL_DEC_BOX) {
     52       if (!exif->empty()) {
     53         size_t remaining = JxlDecoderReleaseBoxBuffer(dec.get());
     54         exif->resize(exif->size() - remaining);
     55         // No need to wait for JXL_DEC_SUCCESS or decode other boxes.
     56         return true;
     57       }
     58       JxlBoxType type;
     59       status = JxlDecoderGetBoxType(dec.get(), type,
     60                                     TO_JXL_BOOL(support_decompression));
     61       if (JXL_DEC_SUCCESS != status) {
     62         fprintf(stderr, "Error, failed to get box type\n");
     63         return false;
     64       }
     65       if (!memcmp(type, "Exif", 4)) {
     66         exif->resize(kChunkSize);
     67         JxlDecoderSetBoxBuffer(dec.get(), exif->data(), exif->size());
     68       }
     69     } else if (status == JXL_DEC_BOX_NEED_MORE_OUTPUT) {
     70       size_t remaining = JxlDecoderReleaseBoxBuffer(dec.get());
     71       output_pos += kChunkSize - remaining;
     72       exif->resize(exif->size() + kChunkSize);
     73       JxlDecoderSetBoxBuffer(dec.get(), exif->data() + output_pos,
     74                              exif->size() - output_pos);
     75     } else if (status == JXL_DEC_SUCCESS) {
     76       if (!exif->empty()) {
     77         size_t remaining = JxlDecoderReleaseBoxBuffer(dec.get());
     78         exif->resize(exif->size() - remaining);
     79         return true;
     80       }
     81       return true;
     82     } else {
     83       fprintf(stderr, "Unknown decoder status\n");
     84       return false;
     85     }
     86   }
     87 }
     88 
     89 bool LoadFile(const char* filename, std::vector<uint8_t>* out) {
     90   FILE* file = fopen(filename, "rb");
     91   if (!file) {
     92     return false;
     93   }
     94 
     95   if (fseek(file, 0, SEEK_END) != 0) {
     96     fclose(file);
     97     return false;
     98   }
     99 
    100   long size = ftell(file);
    101   // Avoid invalid file or directory.
    102   if (size >= LONG_MAX || size < 0) {
    103     fclose(file);
    104     return false;
    105   }
    106 
    107   if (fseek(file, 0, SEEK_SET) != 0) {
    108     fclose(file);
    109     return false;
    110   }
    111 
    112   out->resize(size);
    113   size_t readsize = fread(out->data(), 1, size, file);
    114   if (fclose(file) != 0) {
    115     return false;
    116   }
    117 
    118   return readsize == static_cast<size_t>(size);
    119 }
    120 
    121 bool WriteFile(const char* filename, const uint8_t* data, size_t size) {
    122   FILE* file = fopen(filename, "wb");
    123   if (!file) {
    124     fprintf(stderr, "Could not open %s for writing", filename);
    125     return false;
    126   }
    127   fwrite(data, 1, size, file);
    128   if (fclose(file) != 0) {
    129     return false;
    130   }
    131   return true;
    132 }
    133 
    134 int main(int argc, char* argv[]) {
    135   if (argc != 3) {
    136     fprintf(stderr,
    137             "Usage: %s <jxl> <exif>\n"
    138             "Where:\n"
    139             "  jxl = input JPEG XL image filename\n"
    140             "  exif = output exif filename\n"
    141             "Output files will be overwritten.\n",
    142             argv[0]);
    143     return 1;
    144   }
    145 
    146   const char* jxl_filename = argv[1];
    147   const char* exif_filename = argv[2];
    148 
    149   std::vector<uint8_t> jxl;
    150   if (!LoadFile(jxl_filename, &jxl)) {
    151     fprintf(stderr, "couldn't load %s\n", jxl_filename);
    152     return 1;
    153   }
    154 
    155   std::vector<uint8_t> exif;
    156   if (!DecodeJpegXlExif(jxl.data(), jxl.size(), &exif)) {
    157     fprintf(stderr, "Error while decoding the jxl file\n");
    158     return 1;
    159   }
    160   if (exif.empty()) {
    161     printf("No exif data present in this image\n");
    162   } else {
    163     // TODO(lode): the exif box data contains the 4-byte TIFF header at the
    164     // beginning, check whether this is desired to be part of the output, or
    165     // should be removed.
    166     if (!WriteFile(exif_filename, exif.data(), exif.size())) {
    167       fprintf(stderr, "Error while writing the exif file\n");
    168       return 1;
    169     }
    170     printf("Successfully wrote %s\n", exif_filename);
    171   }
    172   return 0;
    173 }