tor-browser

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

decode_to_jpeg.cc (6564B)


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