libjxl

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

decode_to_jpeg.cc (6520B)


      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 #include "lib/jxl/decode_to_jpeg.h"
      7 
      8 #include <jxl/decode.h>
      9 
     10 #include <algorithm>
     11 #include <cstddef>
     12 #include <cstdint>
     13 #include <cstring>
     14 
     15 #include "lib/jxl/base/span.h"
     16 #include "lib/jxl/base/status.h"
     17 #include "lib/jxl/common.h"  // JPEGXL_ENABLE_TRANSCODE_JPEG
     18 #include "lib/jxl/jpeg/dec_jpeg_data.h"
     19 #include "lib/jxl/jpeg/jpeg_data.h"
     20 
     21 namespace jxl {
     22 
     23 #if JPEGXL_ENABLE_TRANSCODE_JPEG
     24 
     25 JxlDecoderStatus JxlToJpegDecoder::Process(const uint8_t** next_in,
     26                                            size_t* avail_in) {
     27   if (!inside_box_) {
     28     JXL_UNREACHABLE(
     29         "processing of JPEG reconstruction data outside JPEG reconstruction "
     30         "box");
     31   }
     32   Span<const uint8_t> to_decode;
     33   if (box_until_eof_) {
     34     // Until EOF means consume all data.
     35     to_decode = Bytes(*next_in, *avail_in);
     36     *next_in += *avail_in;
     37     *avail_in = 0;
     38   } else {
     39     // Defined size means consume min(available, needed).
     40     size_t avail_recon_in =
     41         std::min<size_t>(*avail_in, box_size_ - buffer_.size());
     42     to_decode = Bytes(*next_in, avail_recon_in);
     43     *next_in += avail_recon_in;
     44     *avail_in -= avail_recon_in;
     45   }
     46   bool old_data_exists = !buffer_.empty();
     47   if (old_data_exists) {
     48     // Append incoming data to buffer if we already had data in the buffer.
     49     buffer_.insert(buffer_.end(), to_decode.data(),
     50                    to_decode.data() + to_decode.size());
     51     to_decode = Bytes(buffer_.data(), buffer_.size());
     52   }
     53   if (!box_until_eof_ && to_decode.size() > box_size_) {
     54     JXL_UNREACHABLE("JPEG reconstruction data to decode larger than expected");
     55   }
     56   if (box_until_eof_ || to_decode.size() == box_size_) {
     57     // If undefined size, or the right size, try to decode.
     58     jpeg_data_ = make_unique<jpeg::JPEGData>();
     59     const auto status = jpeg::DecodeJPEGData(to_decode, jpeg_data_.get());
     60     if (status.IsFatalError()) return JXL_DEC_ERROR;
     61     if (status) {
     62       // Successful decoding, emit event after updating state to track that we
     63       // are no longer parsing JPEG reconstruction data.
     64       inside_box_ = false;
     65       return JXL_DEC_JPEG_RECONSTRUCTION;
     66     }
     67     if (box_until_eof_) {
     68       // Unsuccessful decoding and undefined size, assume incomplete data. Copy
     69       // the data if we haven't already.
     70       if (!old_data_exists) {
     71         buffer_.insert(buffer_.end(), to_decode.data(),
     72                        to_decode.data() + to_decode.size());
     73       }
     74     } else {
     75       // Unsuccessful decoding of correct amount of data, assume error.
     76       return JXL_DEC_ERROR;
     77     }
     78   } else {
     79     // Not enough data, copy the data if we haven't already.
     80     if (!old_data_exists) {
     81       buffer_.insert(buffer_.end(), to_decode.data(),
     82                      to_decode.data() + to_decode.size());
     83     }
     84   }
     85   return JXL_DEC_NEED_MORE_INPUT;
     86 }
     87 
     88 size_t JxlToJpegDecoder::NumExifMarkers(const jpeg::JPEGData& jpeg_data) {
     89   size_t num = 0;
     90   for (size_t i = 0; i < jpeg_data.app_data.size(); ++i) {
     91     if (jpeg_data.app_marker_type[i] == jxl::jpeg::AppMarkerType::kExif) {
     92       num++;
     93     }
     94   }
     95   return num;
     96 }
     97 
     98 size_t JxlToJpegDecoder::NumXmpMarkers(const jpeg::JPEGData& jpeg_data) {
     99   size_t num = 0;
    100   for (size_t i = 0; i < jpeg_data.app_data.size(); ++i) {
    101     if (jpeg_data.app_marker_type[i] == jxl::jpeg::AppMarkerType::kXMP) {
    102       num++;
    103     }
    104   }
    105   return num;
    106 }
    107 
    108 JxlDecoderStatus JxlToJpegDecoder::ExifBoxContentSize(
    109     const jpeg::JPEGData& jpeg_data, size_t* size) {
    110   for (size_t i = 0; i < jpeg_data.app_data.size(); ++i) {
    111     if (jpeg_data.app_marker_type[i] == jxl::jpeg::AppMarkerType::kExif) {
    112       if (jpeg_data.app_data[i].size() < 3 + sizeof(jpeg::kExifTag)) {
    113         // too small for app marker header
    114         return JXL_DEC_ERROR;
    115       }
    116       // The first 4 bytes are the TIFF header from the box contents, and are
    117       // not included in the JPEG
    118       *size = jpeg_data.app_data[i].size() + 4 - 3 - sizeof(jpeg::kExifTag);
    119       return JXL_DEC_SUCCESS;
    120     }
    121   }
    122   return JXL_DEC_ERROR;
    123 }
    124 
    125 JxlDecoderStatus JxlToJpegDecoder::XmlBoxContentSize(
    126     const jpeg::JPEGData& jpeg_data, size_t* size) {
    127   for (size_t i = 0; i < jpeg_data.app_data.size(); ++i) {
    128     if (jpeg_data.app_marker_type[i] == jxl::jpeg::AppMarkerType::kXMP) {
    129       if (jpeg_data.app_data[i].size() < 3 + sizeof(jpeg::kXMPTag)) {
    130         // too small for app marker header
    131         return JXL_DEC_ERROR;
    132       }
    133       *size = jpeg_data.app_data[i].size() - 3 - sizeof(jpeg::kXMPTag);
    134       return JXL_DEC_SUCCESS;
    135     }
    136   }
    137   return JXL_DEC_ERROR;
    138 }
    139 
    140 JxlDecoderStatus JxlToJpegDecoder::SetExif(const uint8_t* data, size_t size,
    141                                            jpeg::JPEGData* jpeg_data) {
    142   for (size_t i = 0; i < jpeg_data->app_data.size(); ++i) {
    143     if (jpeg_data->app_marker_type[i] == jxl::jpeg::AppMarkerType::kExif) {
    144       if (jpeg_data->app_data[i].size() !=
    145           size + 3 + sizeof(jpeg::kExifTag) - 4)
    146         return JXL_DEC_ERROR;
    147       // The first 9 bytes are used for JPEG marker header.
    148       jpeg_data->app_data[i][0] = 0xE1;
    149       // The second and third byte are already filled in correctly
    150       memcpy(jpeg_data->app_data[i].data() + 3, jpeg::kExifTag,
    151              sizeof(jpeg::kExifTag));
    152       // The first 4 bytes are the TIFF header from the box contents, and are
    153       // not included in the JPEG
    154       memcpy(jpeg_data->app_data[i].data() + 3 + sizeof(jpeg::kExifTag),
    155              data + 4, size - 4);
    156       return JXL_DEC_SUCCESS;
    157     }
    158   }
    159   return JXL_DEC_ERROR;
    160 }
    161 JxlDecoderStatus JxlToJpegDecoder::SetXmp(const uint8_t* data, size_t size,
    162                                           jpeg::JPEGData* jpeg_data) {
    163   for (size_t i = 0; i < jpeg_data->app_data.size(); ++i) {
    164     if (jpeg_data->app_marker_type[i] == jxl::jpeg::AppMarkerType::kXMP) {
    165       if (jpeg_data->app_data[i].size() != size + 3 + sizeof(jpeg::kXMPTag))
    166         return JXL_DEC_ERROR;
    167       // The first 9 bytes are used for JPEG marker header.
    168       jpeg_data->app_data[i][0] = 0xE1;
    169       // The second and third byte are already filled in correctly
    170       memcpy(jpeg_data->app_data[i].data() + 3, jpeg::kXMPTag,
    171              sizeof(jpeg::kXMPTag));
    172       memcpy(jpeg_data->app_data[i].data() + 3 + sizeof(jpeg::kXMPTag), data,
    173              size);
    174       return JXL_DEC_SUCCESS;
    175     }
    176   }
    177   return JXL_DEC_ERROR;
    178 }
    179 
    180 #endif  // JPEGXL_ENABLE_TRANSCODE_JPEG
    181 
    182 }  // namespace jxl