tor-browser

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

pgx.cc (4411B)


      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/extras/enc/pgx.h"
      7 
      8 #include <jxl/codestream_header.h>
      9 
     10 #include <cstring>
     11 
     12 #include "lib/extras/packed_image.h"
     13 #include "lib/jxl/base/byte_order.h"
     14 
     15 namespace jxl {
     16 namespace extras {
     17 namespace {
     18 
     19 constexpr size_t kMaxHeaderSize = 200;
     20 
     21 Status EncodeHeader(const JxlBasicInfo& info, char* header,
     22                    int* chars_written) {
     23  if (info.alpha_bits > 0) {
     24    return JXL_FAILURE("PGX: can't store alpha");
     25  }
     26  if (info.num_color_channels != 1) {
     27    return JXL_FAILURE("PGX: must be grayscale");
     28  }
     29  // TODO(lode): verify other bit depths: for other bit depths such as 1 or 4
     30  // bits, have a test case to verify it works correctly. For bits > 16, we may
     31  // need to change the way external_image works.
     32  if (info.bits_per_sample != 8 && info.bits_per_sample != 16) {
     33    return JXL_FAILURE("PGX: bits other than 8 or 16 not yet supported");
     34  }
     35 
     36  // Use ML (Big Endian), LM may not be well supported by all decoders.
     37  *chars_written = snprintf(header, kMaxHeaderSize, "PG ML + %u %u %u\n",
     38                            info.bits_per_sample, info.xsize, info.ysize);
     39  JXL_RETURN_IF_ERROR(static_cast<unsigned int>(*chars_written) <
     40                      kMaxHeaderSize);
     41  return true;
     42 }
     43 
     44 Status EncodeImagePGX(const PackedFrame& frame, const JxlBasicInfo& info,
     45                      std::vector<uint8_t>* bytes) {
     46  char header[kMaxHeaderSize];
     47  int header_size = 0;
     48  JXL_RETURN_IF_ERROR(EncodeHeader(info, header, &header_size));
     49 
     50  const PackedImage& color = frame.color;
     51  const JxlPixelFormat format = color.format;
     52  const uint8_t* in = reinterpret_cast<const uint8_t*>(color.pixels());
     53  JXL_RETURN_IF_ERROR(PackedImage::ValidateDataType(format.data_type));
     54  size_t data_bits_per_sample = PackedImage::BitsPerChannel(format.data_type);
     55  size_t bytes_per_sample = data_bits_per_sample / kBitsPerByte;
     56  size_t num_samples = info.xsize * info.ysize;
     57 
     58  if (info.bits_per_sample != data_bits_per_sample) {
     59    return JXL_FAILURE("Bit depth does not match pixel data type");
     60  }
     61 
     62  std::vector<uint8_t> pixels(num_samples * bytes_per_sample);
     63 
     64  if (format.data_type == JXL_TYPE_UINT8) {
     65    memcpy(pixels.data(), in, num_samples * bytes_per_sample);
     66  } else if (format.data_type == JXL_TYPE_UINT16) {
     67    if (format.endianness != JXL_BIG_ENDIAN) {
     68      const uint8_t* p_in = in;
     69      uint8_t* p_out = pixels.data();
     70      for (size_t i = 0; i < num_samples; ++i, p_in += 2, p_out += 2) {
     71        StoreBE16(LoadLE16(p_in), p_out);
     72      }
     73    } else {
     74      memcpy(pixels.data(), in, num_samples * bytes_per_sample);
     75    }
     76  } else {
     77    return JXL_FAILURE("Unsupported pixel data type");
     78  }
     79 
     80  bytes->resize(static_cast<size_t>(header_size) + pixels.size());
     81  memcpy(bytes->data(), header, static_cast<size_t>(header_size));
     82  memcpy(bytes->data() + header_size, pixels.data(), pixels.size());
     83 
     84  return true;
     85 }
     86 
     87 class PGXEncoder : public Encoder {
     88 public:
     89  std::vector<JxlPixelFormat> AcceptedFormats() const override {
     90    std::vector<JxlPixelFormat> formats;
     91    for (const JxlDataType data_type : {JXL_TYPE_UINT8, JXL_TYPE_UINT16}) {
     92      for (JxlEndianness endianness : {JXL_BIG_ENDIAN, JXL_LITTLE_ENDIAN}) {
     93        formats.push_back(JxlPixelFormat{/*num_channels=*/1,
     94                                         /*data_type=*/data_type,
     95                                         /*endianness=*/endianness,
     96                                         /*align=*/0});
     97      }
     98    }
     99    return formats;
    100  }
    101  Status Encode(const PackedPixelFile& ppf, EncodedImage* encoded_image,
    102                ThreadPool* pool) const override {
    103    JXL_RETURN_IF_ERROR(VerifyBasicInfo(ppf.info));
    104    encoded_image->icc.assign(ppf.icc.begin(), ppf.icc.end());
    105    encoded_image->bitstreams.clear();
    106    encoded_image->bitstreams.reserve(ppf.frames.size());
    107    for (const auto& frame : ppf.frames) {
    108      JXL_RETURN_IF_ERROR(VerifyPackedImage(frame.color, ppf.info));
    109      encoded_image->bitstreams.emplace_back();
    110      JXL_RETURN_IF_ERROR(
    111          EncodeImagePGX(frame, ppf.info, &encoded_image->bitstreams.back()));
    112    }
    113    return true;
    114  }
    115 };
    116 
    117 }  // namespace
    118 
    119 std::unique_ptr<Encoder> GetPGXEncoder() {
    120  return jxl::make_unique<PGXEncoder>();
    121 }
    122 
    123 }  // namespace extras
    124 }  // namespace jxl